1 Options & libs

CSS for scrollable output & Header colors

Turning scientific / Exponential numbers off

options(scipen = 999)
library(tidyverse)
library(tidytuesdayR)
library(ggthemes)
library(glue)
library(scales)

Creating & setting custom theme


theme_viny_bright <- function(){
  
  library(ggthemes)
  
  ggthemes::theme_fivethirtyeight() %+replace%
  
  theme(
    axis.title = element_text(size = 9),
    axis.text = element_text(size = 8),
    legend.text = element_text(size = 7),
    panel.background = element_rect(fill = "white"),
    plot.background = element_rect(fill = "white"),
    strip.background = element_blank(),
    legend.background = element_rect(fill = NA),
    legend.key = element_rect(fill = NA),
    plot.title = element_text(hjust = 0.5,
                              size = 16,
                              face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, size = 10, face = "bold"),
    plot.caption = element_text(hjust = 1, size = 8)
      )
  
  }

theme_set(theme_viny_bright())

sources:

Inspired from: https://www.youtube.com/watch?v=gkZ5n8sfXns

2 Loading data

tt <- tt_load("2021-02-23")

    Downloading file 1 of 2: `earn.csv`
    Downloading file 2 of 2: `employed.csv`
tt

3 EDA

employed <- tt$employed
employed
str(employed)
spec_tbl_df [8,184 x 7] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ industry        : chr [1:8184] "Agriculture and related" "Agriculture and related" "Agriculture and related" "Agriculture and related" ...
 $ major_occupation: chr [1:8184] "Management, professional, and related occupations" "Management, professional, and related occupations" "Service occupations" "Service occupations" ...
 $ minor_occupation: chr [1:8184] "Management, business, and financial operations occupations" "Professional and related occupations" "Protective service occupations" "Service occupations, except protective" ...
 $ race_gender     : chr [1:8184] "TOTAL" "TOTAL" "TOTAL" "TOTAL" ...
 $ industry_total  : num [1:8184] 2349000 2349000 2349000 2349000 2349000 ...
 $ employ_n        : num [1:8184] 961000 58000 13000 94000 12000 96000 931000 10000 33000 42000 ...
 $ year            : num [1:8184] 2020 2020 2020 2020 2020 2020 2020 2020 2020 2020 ...
 - attr(*, "spec")=
  .. cols(
  ..   industry = col_character(),
  ..   major_occupation = col_character(),
  ..   minor_occupation = col_character(),
  ..   race_gender = col_character(),
  ..   industry_total = col_double(),
  ..   employ_n = col_double(),
  ..   year = col_double()
  .. )
summary(employed)
   industry         major_occupation   minor_occupation   race_gender       
 Length:8184        Length:8184        Length:8184        Length:8184       
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
 industry_total        employ_n             year     
 Min.   :   18000   Min.   :       0   Min.   :2015  
 1st Qu.:  767250   1st Qu.:    9000   1st Qu.:2016  
 Median : 2484000   Median :   65000   Median :2018  
 Mean   : 5077105   Mean   :  461552   Mean   :2018  
 3rd Qu.: 7643000   3rd Qu.:  373000   3rd Qu.:2019  
 Max.   :35894000   Max.   :20263000   Max.   :2020  
 NA's   :660        NA's   :660                      
employed %>% 
  mutate_if(is.character, as.factor) %>% 
  summary()
                          industry   
 Agriculture and related      : 396  
 Construction                 : 396  
 Durable goods                : 396  
 Education and health services: 396  
 Financial activities         : 396  
 (Other)                      :5874  
 NA's                         : 330  
                                                     major_occupation
 Management, professional, and related occupations           :1488   
 Natural resources, construction, and maintenance occupations:2232   
 Production, transportation, and material moving occupations :1488   
 Sales and office occupations                                :1488   
 Service occupations                                         :1488   
                                                                     
                                                                     
                                          minor_occupation
 Construction and extraction occupations          : 744   
 Farming, fishing, and forestry occupations       : 744   
 Installation, maintenance, and repair occupations: 744   
 Office and administrative support occupations    : 744   
 Production occupations                           : 744   
 Professional and related occupations             : 744   
 (Other)                                          :3720   
                    race_gender   industry_total        employ_n       
 Asian                    :1254   Min.   :   18000   Min.   :       0  
 Black or African American:1386   1st Qu.:  767250   1st Qu.:    9000  
 Men                      :1386   Median : 2484000   Median :   65000  
 TOTAL                    :1386   Mean   : 5077105   Mean   :  461552  
 White                    :1386   3rd Qu.: 7643000   3rd Qu.:  373000  
 Women                    :1386   Max.   :35894000   Max.   :20263000  
                                  NA's   :660        NA's   :660       
      year     
 Min.   :2015  
 1st Qu.:2016  
 Median :2018  
 Mean   :2018  
 3rd Qu.:2019  
 Max.   :2020  
               

looks like we have NA’s in data

3.1 Missing Values

sapply(employed, function(x) sum(is.na(x))) %>% 
  as.data.frame()
library(naniar)
employed %>% 
  naniar::gg_miss_upset()

3.2 Cols Freq

table(employed$industry) %>% 
  as.data.frame() %>% 
  arrange(desc(Freq)) %>% 
  
  ggplot(aes(Freq, fct_reorder(Var1, Freq), fill = Var1))  +
  geom_col() +
  theme(legend.position = "none")

top_freq_elements <- function(x){
  
  table(x) %>% 
    as.data.frame() %>% 
    arrange(desc(Freq)) %>% 
    
    ggplot(aes(Freq, fct_reorder(x, Freq), fill = x))  +
    geom_col() +
    theme(legend.position = "none")
}
employed %>% 
  select_if(is.character) %>% 
  map(., .f = top_freq_elements)
$industry

$major_occupation

$minor_occupation

$race_gender

employed %>% 
  count(year)
employed %>% 
  count(industry) %>% 
  ggplot(aes(x = n, y = industry, fill = industry)) +
  geom_col() +
  theme(legend.position = "none")

from: onenote:///\\VINY-PC\Users\viny\Documents\OneNote%20Notebooks\R%20Learning%20&%20Notes\R%20Visualization.one#count()%20%20plot%20frequency%20of%20each%20variable%20in%20a%20function&section-id={C245D183-2D71-46D1-BCBE-2C1A047C220B}&page-id={FEB1F723-D8B8-4DB8-9BA3-ACD8DF96F454}&object-id={A46CDF35-1F4D-45E3-A63B-A89DC402039A}&10

var_freq_plot_fn <- function(df, selected_var){
  df %>% 
    # select_if(is.character) %>%
    count(.data[[selected_var]]) %>%
    # as_tibble() %>%
    
    ggplot(aes(x = n, y = .data[[selected_var]], fill = .data[[selected_var]])) +
    geom_col() +
    theme(legend.position = "none")
}
purrr::map(.x = names(employed %>% select_if(is.character)), 
           .f = var_freq_plot_fn, 
           df = employed)
[[1]]

[[2]]

[[3]]

[[4]]

var_freq_plot_fn <- function(df){
  purrr::map(df %>% 
               select_if(is.character) %>% 
               names, ~
  df %>% 
    count(.data[[.x]]) %>%
    ggplot(aes(x = n, y = .data[[.x]], fill = .data[[.x]])) +
    geom_col() +
    theme(legend.position = "none"))
}
var_freq_plot_fn(df = employed)
[[1]]

[[2]]

[[3]]

[[4]]

3.3 sankey highcharter

from: https://www.youtube.com/watch?v=k-IN6HBhgq4&t=142s

library(highcharter)
highcharter::data_to_sankey(data = (employed %>% 
                                      select(industry, major_occupation))) %>% 
  hchart(., "sankey", name = "Industries to Occupation")
highcharter::data_to_sankey(data = (employed %>% 
                                      select(major_occupation, minor_occupation))) %>% 
  hchart(., "sankey", name = "Major occupation to minor occupation") %>% 
  hc_add_theme(hc_theme_monokai()) %>% 
  hc_title(text = "Industry to Occupation sankey plot")

3.4 Employment Change

employed %>% 
  na.omit() %>% 
  group_by(year) %>% 
  summarise(employment_yrwise = sum(employ_n))
employed %>% 
  na.omit() %>% 
  group_by(year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0))
employed %>% 
  na.omit() %>% 
  group_by(year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0),
         line_color = ifelse(employ_change >= 0, "blue","red")) %>% 
  
  ggplot(aes(x = year, y = employ_change, 
             label = round(employ_change*100, digits = 2)
             ,col = line_color
             )) +
  geom_line(group=1) +
  geom_point() +
  scale_y_continuous(labels = scales::percent_format(),
                     limits = c(-0.08, 0.02) ) +
  scale_color_identity() +
  geom_text(nudge_y = .005) +
  labs(title = "Yearly % Change in Employment")

from: https://stackoverflow.com/questions/44947806/how-can-i-fill-the-space-between-valuesgeom-line-and-an-intercept-with-ggplot2/44948631#44948631

employment_yr_change <- employed %>% 
  na.omit() %>% 
  group_by(year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0))  
  
  
employment_yr_change %>% 
  ggplot(aes(x = year, y = employ_change, 
             label = round(employ_change*100, digits = 2)
             # ,col = line_color
             )) +
  # geom_line(group=1) +
  # geom_point() +
  geom_ribbon(aes(ymin=pmin(employment_yr_change$employ_change,0), ymax=0), fill="red", col="red", alpha=0.5) +
  geom_ribbon(aes(ymin=0, ymax=pmax(employment_yr_change$employ_change,0)), fill="green", col="green", alpha=0.5) +
  
  scale_y_continuous(labels = scales::percent_format(),
                     limits = c(-0.08, 0.02) ) +
  scale_color_manual(values = c("blue","red")) +
  geom_text(nudge_y = .005) +
  labs(title = "Yearly % Change in Employment")

3.4.1 distinct color line

Coloring positive & negative line with separate colors

from: https://stackoverflow.com/questions/66370513/how-to-color-geom-line-geom-point-properly-based-on-condition-if-less-than/66371746#66371746

create function

divide_line <- function(x, y, at = 0) {
  df <- data.frame(x, ymin = at, ymax = y)
  df$sign <- sign(df$ymax - df$ymin)
  df <- df[order(df$x), ]
  df$id <- with(rle(df$sign), rep.int(seq_along(values), lengths))
  
  crossover <- which(c(FALSE, diff(df$id) == 1))
  crossover <- sort(c(crossover, crossover - 1))
  splitter  <- rep(seq_len(length(crossover) / 2), each = 2)
  crossover <- lapply(split(df[crossover, ], splitter), find_isect)
  
  df <- do.call(rbind, c(list(df), crossover))
  df[order(df$x),]
}
find_isect <- function(df) {
  list2env(df, envir = rlang::current_env())
  dx <- x[1] - x[2]
  dy <- ymin[1] - ymin[2]
  t <- (-1 * (ymin[1] - ymax[1]) * dx) / (dx * (ymax[1] - ymax[2]) - dy * dx)
  df$x <- x[1] + t * -dx
  df$ymin <- df$ymax <- ymin[1] + t * -dy
  return(df)
}

create df

df <- divide_line(employment_yr_change$year, employment_yr_change$employ_change, at = 0)

df

create plot

ggplot(df, aes(x, ymax, group = id, colour = as.factor(sign),
               label = paste0(round(ymax*100, digits = 2),"%") )
       )+
  geom_line(size = .9) +
  geom_point() +
  scale_y_continuous(labels = percent_format(), 
                     limits = c(-.08,.02)
                     ) +
  geom_text(nudge_y = .005) +
  labs(title = "Yearly % Change in Employment")

ggplot(df, aes(x, ymax, group = id, colour = as.factor(sign),
               label = paste0(round(ymax*100, digits = 2),"%") )
       )+
  geom_line(size = .9, aes(linetype = as.factor(id))) +
  geom_point() +
  scale_linetype_manual(values=c(2, 1, 3)) +
  scale_y_continuous(labels = percent_format(), 
                     limits = c(-.08,.02)
                     ) +
  geom_text(nudge_y = .005) +
  labs(title = "Yearly % Change in Employment")

3.5 Emp comparison charts

balloon plot from: http://www.sthda.com/english/articles/32-r-graphics-essentials/129-visualizing-multivariate-categorical-data/

https://rpkgs.datanovia.com/ggpubr/reference/ggballoonplot.html

library(ggpubr)
library(viridis)
ggpubr::ggballoonplot(employed, x = "major_occupation", y = "industry", 
                      size = "employ_n", fill = "employ_n") +
  scale_fill_viridis_c(option = "C")

removing irrelevant categories from industries

ggpubr::ggballoonplot(employed %>% 
                      filter(!industry %in% c(NA, "Men","Women","White","Black or African American", "Asian")) %>% 
                        mutate(major_occupation = str_wrap(major_occupation, width = 25),
                               industry = str_wrap(industry, width = 25)), 
                      x = "major_occupation", y = "industry", 
                      size = "employ_n", shape = 16) +
  scale_fill_viridis_c(option = "C") +
  labs(title = "Industry wise Employment Comparison")

ggpubr::ggballoonplot(employed %>% 
                      filter(!industry %in% c(NA, "Men","Women","White","Black or African American", "Asian")) %>%  
                        mutate(industry = str_wrap(industry, width = 25)), 
                      x = "year", y = "industry", 
                      size = "employ_n", fill = "employ_n") +
  scale_fill_viridis_c(option = "C") +
  labs(title = "Industry Employment Comparison year wise")

ggpubr::ggballoonplot(employed %>% 
                      filter(!industry %in% c(NA, "Men","Women","White","Black or African American", "Asian")), 
                      x = "major_occupation", y = "industry", 
                      size = "employ_n", fill = "employ_n",  shape = 21, 
                      facet.by = "year", ggtheme = theme_bw()) +
  
  scale_fill_viridis_c(option = "C") +
  # gradient_fill(c("blue", "white", "red"))
  
  labs(title = "Yearly Industry & occupation wise employment comparison")

employed$minor_occupation %>% unique()
 [1] "Management, business, and financial operations occupations" 
 [2] "Professional and related occupations"                       
 [3] "Protective service occupations"                             
 [4] "Service occupations, except protective"                     
 [5] "Sales and related occupations"                              
 [6] "Office and administrative support occupations"              
 [7] "Farming, fishing, and forestry occupations"                 
 [8] "Construction and extraction occupations"                    
 [9] "Installation, maintenance, and repair occupations"          
[10] "Production occupations"                                     
[11] "Transportation and material moving occupations"             
[12] "Manage-ment, business, and financial operations occupations"
ggpubr::ggballoonplot(employed, x = "major_occupation", y = "minor_occupation", 
                      size = "employ_n", fill = "employ_n",  shape = 21, 
                      facet.by = "year", ggtheme = theme_bw()) +
  
  scale_fill_viridis_c(option = "C") +
  # gradient_fill(c("blue", "white", "red"))
  
  labs(title = "Yearly occupation wise employment comparison")

As we can see in above chart there are two Management, Manage-ment & needs data cleaning and re plotting

employed <- employed %>% 
  mutate(minor_occupation = str_replace(employed$minor_occupation, "Manage-ment", "Management")) 

employed$minor_occupation %>% unique()
 [1] "Management, business, and financial operations occupations"
 [2] "Professional and related occupations"                      
 [3] "Protective service occupations"                            
 [4] "Service occupations, except protective"                    
 [5] "Sales and related occupations"                             
 [6] "Office and administrative support occupations"             
 [7] "Farming, fishing, and forestry occupations"                
 [8] "Construction and extraction occupations"                   
 [9] "Installation, maintenance, and repair occupations"         
[10] "Production occupations"                                    
[11] "Transportation and material moving occupations"            
ggpubr::ggballoonplot(employed, x = "major_occupation", y = "minor_occupation", 
                      size = "employ_n", fill = "employ_n",  shape = 21, 
                      facet.by = "year", ggtheme = theme_bw()) +
  
  scale_fill_viridis_c(option = "C") +
  # gradient_fill(c("blue", "white", "red"))
  
  labs(title = "Yearly occupation wise employment comparison")

3.6 Adding dimension

employed <- employed %>% 
  mutate(dimension = case_when(race_gender == "TOTAL" ~ "Total",
                               race_gender %in% c("Men", "Women") ~ "Gender",
                               TRUE ~ "Race")) 
employed %>% 
  select(dimension) %>% 
  table()
.
Gender   Race  Total 
  2772   4026   1386 

3.7 Industry Emp Comparison

employed_ind_cleaned <- employed %>% 
  na.omit() %>% 
  filter(dimension == "Total") %>% 
  mutate(industry = fct_lump(industry, 11, w = employ_n),
         industry = fct_reorder(industry, employ_n, sum))

3.7.1 Industry Stack plot

employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = industry)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "right", legend.direction = "vertical") +
  labs(title = "Number of employs industry wise across the years") +
  scale_fill_pander()

3.7.2 Industry circular bar

employed_ind_cleaned %>% 
  filter(year == 2020) %>% 
  # summarise(max(employ_n))
  
  ggplot(aes(x = industry, y = employ_n, fill = industry)) +
  geom_bar(stat = "identity") +
  # scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "none") +
  ylim(0,25000000) +
  coord_polar(start = 0) +
  labs(title = "Number of employs industry wise in 2020")

employed_ind_cleaned %>% 
  filter(year == 2020) %>% 
  
  ggplot(aes(x = fct_reorder(industry, employ_n, sum), y = employ_n, fill = industry)) +
  geom_col() +
  # scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6),
  #                    limits = -50,20000000) +
  theme_minimal() +
  theme(legend.position = "none") +
  ylim(-5000000,25000000) +
  coord_polar(start = 240) +
  labs(title = "Number of employs industry wise in 2020")

3.7.3 Industry facet

employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = industry)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "none",
        strip.text = element_text(size=8, face = "bold")) +
  labs(title = "Number of employs industry wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ industry) +
  scale_fill_pander()

employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = industry)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "none",
        strip.text = element_text(size=8, face = "bold")) +
  labs(title = "Number of employs industry wise across the years",
       subtitle = "Free scale comparison") +
  facet_wrap(~ industry, scales = "free_y") +
  scale_fill_pander() 


employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0)),
         industry = str_wrap(industry, width = 20)) %>% 
  
  ggplot(aes(x = year, y = employ_change, col = industry)) +
  geom_line(size = .9) +
  scale_y_continuous(limits = c(-4000000,2000000),
                     labels = unit_format(unit = "M", scale = 1e-6)) +
  facet_wrap(~ industry) +
  
  labs(title = "Yearly Actual Change in employment count Industry wise") +
  theme(legend.position = "none", panel.grid.major = element_blank(),
        strip.text = element_text(size=8, face = "bold")) +
  guides(x = guide_axis(n.dodge = 3))

3.7.4 Industry % change


employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise),
         industry = str_wrap(industry, width = 20) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0) %>% round(digits = 4)) %>% 
  
  ggplot(aes(x = year, y = employ_change, fill = industry)) +
  geom_col() +
  scale_y_continuous(labels = percent_format()) +
  facet_wrap(~ industry) +
  
  labs(title = "Yearly % Change in employment count Industry wise") +
  theme(legend.position = "none",
        strip.text = element_text(size=8, face = "bold"))

ggsave("emp_change_industry.jpg")

employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise),
         industry = str_wrap(industry, width = 20) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0) %>% round(digits = 4)) %>% 
  
  ggplot(aes(x = year, y = employ_change, fill = industry)) +
  geom_col() +
  coord_flip() +
  scale_y_continuous(labels = percent_format()) +
  facet_wrap(~ industry) +
  
  labs(title = "Yearly % Change in employment count Industry wise") +
  theme(legend.position = "none",
        strip.text = element_text(size=8, face = "bold"))

ggsave("emp_change_industry_flipped.jpg")

employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise),
         industry = str_wrap(industry, width = 20) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0) %>% round(digits = 4)) %>% 
  
  ggplot(aes(x = year, y = employ_change, col = industry)) +
  geom_line(size=.9) +
  scale_y_continuous(labels = percent_format()) +
  facet_wrap(~ industry) +
  
  labs(title = "Yearly % Change in employment count Industry wise") +
  theme(legend.position = "none", 
        panel.grid.major = element_blank(),
        strip.text = element_text(size=8, face = "bold"),
        axis.text.x = element_text(angle = 90))

from: https://www.youtube.com/watch?v=_7J6BbDgqrA

but is not working as expected


employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise, default = 0))/
           lag(employment_yrwise),
         industry = str_wrap(industry, width = 20) ) %>% 
  mutate(employ_change = replace(employ_change, is.na(employ_change), 0) %>% round(digits = 4)) %>% 
  
  ggplot() +
  geom_col(aes(x = year, y = employ_change * 20000000, fill = employ_change > 0), alpha = 0.4) +
  geom_line(aes(x = year, y = employment_yrwise), group =1) +
  geom_point(aes(x = year, y = employment_yrwise, col = employ_change > 0)) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  facet_wrap(~ industry) +
  
  labs(title = "Yearly % Change in employment count Industry wise") +
  theme(legend.position = "none", panel.grid.major = element_blank(),
        strip.text = element_text(size=8, face = "bold")) +
  guides(x = guide_axis(n.dodge = 3))

by adding geom_text this worked


employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise))/
           lag(employment_yrwise) ) %>% 
  na.omit() %>%
  mutate(industry = str_wrap(industry, width = 20)) %>% 
   
  
  ggplot() +
  geom_col(aes(x = year, y = employ_change * 20000000, fill = employ_change > 0), alpha = 0.4) +
  geom_line(aes(x = year, y = employment_yrwise), group =1) +
  geom_point(aes(x = year, y = employment_yrwise, col = employ_change > 0)) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  
  facet_wrap(~ industry) +
  labs(title = "Industry wise Yearly % Change & # in employment",
       y = "# Employment (in Millions)") +
  theme(legend.position = "none", panel.grid.major = element_blank(),
        strip.text = element_text(size=8)) +
  guides(x = guide_axis(n.dodge = 2)) +
  
  geom_text(aes(x = year, y = employ_change, label = paste0(round(employ_change*100,
                                                                  digits=1),"%")
                , col = employ_change > 0), 
            nudge_y = -3000000, size = 2.2, angle = 45)

ggsave("actual_perc_change_in_emp.jpg")

adding geom_text to geom_line


employed_ind_cleaned %>% 
  group_by(industry, year) %>% 
  summarise(employment_yrwise = sum(employ_n)) %>% 
  mutate(employ_change = (employment_yrwise - lag(employment_yrwise))/
           lag(employment_yrwise) ) %>% 
  na.omit() %>%
  mutate(industry = str_wrap(industry, width = 20)) %>% 
  
  ggplot() +
  geom_col(aes(x = year, y = employ_change * 20000000, fill = employ_change > 0), alpha = 0.4) +
  geom_line(aes(x = year, y = employment_yrwise), group =1) +
  geom_point(aes(x = year, y = employment_yrwise, col = employ_change > 0)) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  
  facet_wrap(~ industry) +
  labs(title = "Industry wise Yearly % Change & # in employment",
       y = "# Employment (in Millions)") +
  theme(legend.position = "none", panel.grid.major = element_blank(),
        strip.text = element_text(size=8)) +
  guides(x = guide_axis(n.dodge = 2)) +
  
  geom_text(aes(x = year, y = (employ_change * 20000000) - 3000000, 
                label = paste0(round(employ_change*100,
                                     digits=1),"%")
                , col = employ_change > 0), 
            size = 2, angle = 45) +
  
  geom_text(aes(x = year, y = employment_yrwise + 5000000, 
                label = paste(round(employment_yrwise/1000000, digits=1), "M")
                , col = employ_change > 0), 
            size = 2, angle = 35)

ggsave("actual_perc_change_in_emp2.jpg")

3.8 Occupation Emp Comparison

3.8.1 Major Occupation


employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = major_occupation)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  # theme(legend.position = "right", legend.direction = "vertical") +
  labs(title = "Number of employs in Major occupation, Industry wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ industry)


employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = major_occupation)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "none",
        strip.text = element_text(size=7)) +
  labs(title = "Number of employs in Major occupation, Industry wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ major_occupation)

3.8.2 Minor occupation


employed_ind_cleaned %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = minor_occupation)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  # theme(legend.position = "right", legend.direction = "vertical") +
  labs(title = "Number of employs in Minor occupation, Industry wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ industry)


employed_ind_cleaned %>% 
  mutate(minor_occupation = str_wrap(minor_occupation, width = 25)) %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = minor_occupation)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(legend.position = "none",
        strip.text = element_text(size=8)) +
  labs(title = "Number of employs in Minor occupation, Industry wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ minor_occupation)

3.8.3 Major & Minor


employed_ind_cleaned %>% 
  mutate(major_occupation = str_wrap(major_occupation, width = 30)) %>%
  
  ggplot(aes(x = year, y = employ_n, fill = minor_occupation)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(strip.text = element_text(size=8)) +
  labs(title = "Number of employs in Minor occupation, Major occupation wise across the years",
       subtitle = "Keeping scale fixed for industry level comparison") +
  facet_wrap(~ major_occupation)

3.9 Gender Industry Comparison

employed %>% 
  na.omit() %>% 
  filter(dimension == "Gender") %>% 
  
  ggplot(aes(x = year, y = employ_n, fill = race_gender)) +
  geom_col() +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme(strip.text = element_text(size=7)) +
  labs(title = "Number of employs industry wise across the years",
       subtitle = "Colored by Gender") +
  facet_wrap(~ industry) +
  scale_fill_tableau()

employed %>% 
  na.omit() %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_lump(industry, 11, w = employ_n)) %>% 
  group_by(year, industry, race_gender) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  ggplot(aes(x = year, y = employ_n, col = race_gender)) +
  geom_line(size = 0.9) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        strip.text = element_text(size=7),
        legend.position = "top") +
  labs(title = "Number of employs industry wise based on Gender across the years") +
  facet_wrap(~ industry) +
  guides(x = guide_axis(n.dodge = 3)) +
  scale_color_tableau()

employed %>% 
  na.omit() %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_lump(industry, 11, w = employ_n)) %>% 
  group_by(year, industry, race_gender) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  ggplot(aes(x = year, y = employ_n, col = race_gender)) +
  geom_line(size = 0.9) +
  scale_y_log10(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        strip.text = element_text(size=7),
        legend.position = "top") +
  labs(title = "Log of employs industry wise based on Gender across the years") +
  facet_wrap(~ industry) +
  guides(x = guide_axis(n.dodge = 3)) +
  scale_color_tableau()

employed %>% 
  na.omit() %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_lump(industry, 15, w = employ_n)) %>% 
  group_by(year, industry, race_gender) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  ggplot(aes(x = year, y = employ_n, col = race_gender)) +
  geom_line(size = 0.9) +
  scale_y_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  theme_bw() +
  theme(panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        strip.text = element_text(size=7),
        legend.position = "top") +
  labs(title = "Number of employs industry wise based on Gender across the years",
       subtitle = "(Free scale comparison)") +
  facet_wrap(~ industry, scales = "free_y") +
  guides(x = guide_axis(n.dodge = 3)) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE))

3.10 2019-2020 Emply change

compare_2019_2020 <- employed %>% 
  na.omit() %>% 
  filter(year %in% c(2019, 2020)) %>% 
  arrange(year) %>% 
  group_by(industry, year, dimension, race_gender) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  group_by(industry, dimension, race_gender) %>% 
  summarise(ratio = last(employ_n) / first(employ_n),
            change = ratio -1,
            employed_2019 = first(employ_n),
            employ_2020 = last(employ_n)) %>%
  mutate(industry = fct_reorder(industry, change, sum)) %>% 
  ungroup()

compare_2019_2020

compare_2019_2020 %>% 
  filter(dimension == "Total") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, fill = industry)) +
  geom_col() +
  theme(legend.position = "none") +
  scale_x_continuous(labels = percent_format()) +
  labs(title = "Industry %Change in emply. from 2019 to 2020",
       y = "") 


compare_2019_2020 %>% 
  filter(dimension == "Total") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, fill = industry)) +
  geom_col() +
  theme(legend.position = "none") +
  scale_x_continuous(labels = percent_format()) +
  labs(title = "Industry %Change in emply. from 2019 to 2020",
       y = "") +
  geom_label(aes(label = employ_2020), size = 3, color = "white")


compare_2019_2020 %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, fill = race_gender)) +
  geom_col() +
  theme(legend.position = "right", legend.direction = "vertical") +
  scale_x_continuous(labels = percent_format()) +
  scale_fill_tableau() +
  labs(title = "Industry %Change in emply. from 2019 to 2020",
       y = "")


compare_2019_2020 %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, fill = race_gender)) +
  geom_col(position = "dodge") +
  theme(legend.position = "right", legend.direction = "vertical") +
  scale_x_continuous(labels = percent_format()) +
  scale_fill_tableau(guide = guide_legend(reverse = TRUE)) +
  labs(title = "Industry %Change in emply. from 2019 to 2020",
       y = "")

3.10.1 lollypop plot

3.10.1.1 Gender


compare_2019_2020 %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, col = race_gender)) +
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0) +
  geom_point(aes(size = employed_2019)) +
  theme(legend.position = "right", legend.direction = "vertical") +
  scale_x_continuous(labels = percent_format()) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  labs(title = "Industry %Change in emply. from 2019 to 2020",
       y = "", col = "Gender", size = "2019 employ #")


compare_2019_2020 %>% 
  filter(dimension == "Gender") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format()) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  expand_limits(x = .2) +
  
  labs(title = str_wrap("% Change in Emply. for Industries", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Gender",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020",
       col = "Gender" )

ggsave(filename = "Industry-gender-lolypop.jpg")

3.10.1.2 Race


compare_2019_2020 %>% 
  filter(dimension == "Race") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(x = change, y = industry, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format()) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  
  labs(title = str_wrap("% Change in Emply. for Industries", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Race",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020", 
       col = "Race")

ggsave(filename = "Industry-race-lolypop.jpg")

3.10.2 major occupation

3.10.2.1 Gender


employed %>% 
  na.omit() %>% 
  filter(year %in% c(2019, 2020)) %>% 
  arrange(year) %>% 
  group_by(year, dimension, race_gender, major_occupation) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  group_by(major_occupation, dimension, race_gender) %>% 
  summarise(ratio = last(employ_n) / first(employ_n),
            change = ratio -1,
            employed_2019 = first(employ_n),
            employ_2020 = last(employ_n)) %>%
  mutate(industry = fct_reorder(major_occupation, change, sum)) %>% 
  ungroup() %>% 
  
  filter(dimension == "Gender") %>%
  
  mutate(major_occupation = fct_reorder(major_occupation, change)) %>% 
  
  ggplot(aes(x = change, y = major_occupation, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format(), limits = c(-.2,.1)) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  
  labs(title = str_wrap("% Change in Emply. by Major Occupation", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Gender",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020", 
       col = "Gender")

3.10.2.2 Race


employed %>% 
  na.omit() %>% 
  filter(year %in% c(2019, 2020)) %>% 
  arrange(year) %>% 
  group_by(year, dimension, race_gender, major_occupation) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  group_by(major_occupation, dimension, race_gender) %>% 
  summarise(ratio = last(employ_n) / first(employ_n),
            change = ratio -1,
            employed_2019 = first(employ_n),
            employ_2020 = last(employ_n)) %>%
  mutate(industry = fct_reorder(major_occupation, change, sum)) %>% 
  ungroup() %>% 
  
  filter(dimension == "Race") %>% 
  
  mutate(major_occupation = fct_reorder(major_occupation, change)) %>% 
  
  ggplot(aes(x = change, y = major_occupation, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format(), limits = c(-.2,.1)) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  
  labs(title = str_wrap("% Change in Emply. by Major Occupation", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Race",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020", 
       col = "Race")

3.10.3 minor occupation

3.10.3.1 Gender


employed %>% 
  na.omit() %>% 
  filter(year %in% c(2019, 2020)) %>% 
  arrange(year) %>% 
  group_by(year, dimension, race_gender, minor_occupation) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  group_by(minor_occupation, dimension, race_gender) %>% 
  summarise(ratio = last(employ_n) / first(employ_n),
            change = ratio -1,
            employed_2019 = first(employ_n),
            employ_2020 = last(employ_n)) %>%
  mutate(industry = fct_reorder(minor_occupation, change, sum)) %>% 
  ungroup() %>% 
  
  filter(dimension == "Gender") %>%
  
  mutate(minor_occupation = fct_reorder(minor_occupation, change)) %>% 
  
  ggplot(aes(x = change, y = minor_occupation, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format(), limits = c(-.2,.1)) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  
  labs(title = str_wrap("% Change in Emply. by Minor Occupation", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Gender",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020", 
       col = "Gender")

3.10.3.2 Race


employed %>% 
  na.omit() %>% 
  filter(year %in% c(2019, 2020)) %>% 
  arrange(year) %>% 
  group_by(year, dimension, race_gender, minor_occupation) %>% 
  summarise(employ_n = sum(employ_n)) %>% 
  
  group_by(minor_occupation, dimension, race_gender) %>% 
  summarise(ratio = last(employ_n) / first(employ_n),
            change = ratio -1,
            employed_2019 = first(employ_n),
            employ_2020 = last(employ_n)) %>%
  mutate(industry = fct_reorder(minor_occupation, change, sum)) %>% 
  ungroup() %>% 
  
  filter(dimension == "Race") %>% 
  
  mutate(minor_occupation = fct_reorder(minor_occupation, change)) %>% 
  
  ggplot(aes(x = change, y = minor_occupation, col = race_gender)) +
  
  geom_errorbarh(aes(xmin = 0, xmax = change), height = 0,
             position = position_dodge(width = .6)) +
  geom_point(aes(size = employed_2019),
             position = position_dodge(width = .6)) +
  geom_vline(xintercept = 0, lty = 2, size = 1) +
  
  theme(legend.position = "top",
        panel.grid.major = element_blank()) +
  scale_x_continuous(labels = percent_format(), limits = c(-.2,.1)) +
  scale_color_tableau(guide = guide_legend(reverse = TRUE)) +
  scale_size_continuous(guide = FALSE) +
  
  labs(title = str_wrap("% Change in Emply. by Minor Occupation", 35),
       subtitle = "(from: 2019 to 2020) \n \nSize is proportional to emply # in 2019 \n Lollypop Respresents Race",
       caption = "Created by ViSa",
       y = "", x = "Change in employment from 2019-2020", 
       col = "Race")

3.10.4 Industry wise % change

3.10.4.1 Total

library(ggrepel)
compare_2019_2020 %>% 
  filter(dimension == "Total") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(employed_2019, change)) +
  geom_point() +
  geom_text_repel(aes(label = industry), size = 3) +
  geom_hline(yintercept = 0, lty = 2, col = "red") +
  
  scale_x_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  scale_y_continuous(labels = percent_format()) +
  
  labs(title = "Overall % Emply Change for Industries",
       subtitle = "(in: 2019 to 2020)")

3.10.4.2 Race

compare_2019_2020 %>% 
  filter(dimension == "Race",
         race_gender == "Asian") %>% 
  mutate(industry = fct_reorder(industry, change)) %>% 
  
  ggplot(aes(employed_2019, change)) +
  geom_point() +
  geom_text_repel(aes(label = industry), size = 3) +
  geom_hline(yintercept = 0, lty = 2, col = "red") +
  
  scale_x_continuous(labels = unit_format(unit = "M", scale = 1e-6)) +
  scale_y_continuous(labels = percent_format()) +
  
  labs(title = "Emply % Change for Asians in Industry",
       subtitle = "(in: 2019 to 2020)")

3.11 More Exploration

employed %>% 
  na.omit() %>% pull(race_gender) %>% 
  table()
.
                    Asian Black or African American                       Men 
                     1254                      1254                      1254 
                    TOTAL                     White                     Women 
                     1254                      1254                      1254 
  
employed %>% 
  na.omit() %>% pull(dimension) %>% 
  table()
.
Gender   Race  Total 
  2508   3762   1254 

Seems like we dont have data for Gender among Races, so skiping the analysis of combination of both.

employed
employed %>% 
  pull(race_gender) %>% 
  table()
.
                    Asian Black or African American                       Men 
                     1254                      1386                      1386 
                    TOTAL                     White                     Women 
                     1386                      1386                      1386 

3.12 End of this EDA

LS0tDQp0aXRsZTogIlRpZHkgdHVlc2RheSAtIFVuZW1wbG95bWVudCBFREEiDQpvdXRwdXQ6IA0KICBodG1sX25vdGVib29rOg0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogICAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19kZXB0aDogNg0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNicNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQojIE9wdGlvbnMgJiBsaWJzDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZHBpID0gMzAwLCBvdXQud2lkdGggPSAiMTAwJSIsYXR0ci5vdXRwdXQ9J3N0eWxlPSJtYXgtaGVpZ2h0OiAzMDBweDsiJykNCmBgYA0KDQpDU1MgZm9yIHNjcm9sbGFibGUgb3V0cHV0ICYgSGVhZGVyIGNvbG9ycw0KDQpgYGB7Y3NzLCBlY2hvPUZBTFNFfQ0KLnNjcm9sbC0xMDAgew0KICBtYXgtaGVpZ2h0OiAxMDBweDsNCiAgb3ZlcmZsb3cteTogYXV0bzsNCiAgYmFja2dyb3VuZC1jb2xvcjogaW5oZXJpdDsNCn0NCg0KYGBgDQoNClR1cm5pbmcgc2NpZW50aWZpYyAvIEV4cG9uZW50aWFsIG51bWJlcnMgb2ZmDQoNCmBgYHtyfQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkodGlkeXR1ZXNkYXlSKQ0KbGlicmFyeShnZ3RoZW1lcykNCmxpYnJhcnkoZ2x1ZSkNCmxpYnJhcnkoc2NhbGVzKQ0KYGBgDQoNCkNyZWF0aW5nICYgc2V0dGluZyBjdXN0b20gdGhlbWUNCg0KYGBge3J9DQoNCnRoZW1lX3ZpbnlfYnJpZ2h0IDwtIGZ1bmN0aW9uKCl7DQogIA0KICBsaWJyYXJ5KGdndGhlbWVzKQ0KICANCiAgZ2d0aGVtZXM6OnRoZW1lX2ZpdmV0aGlydHllaWdodCgpICUrcmVwbGFjZSUNCiAgDQogIHRoZW1lKA0KICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLA0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiksDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLA0KICAgIGxlZ2VuZC5rZXkgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BKSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE2LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiKSwNCiAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplID0gOCkNCiAgICAgICkNCiAgDQogIH0NCg0KdGhlbWVfc2V0KHRoZW1lX3ZpbnlfYnJpZ2h0KCkpDQpgYGANCg0KKipzb3VyY2VzOioqDQoNCkluc3BpcmVkIGZyb206IDxodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PWdrWjVuOHNmWG5zPg0KDQojIExvYWRpbmcgZGF0YQ0KDQpgYGB7cn0NCnR0IDwtIHR0X2xvYWQoIjIwMjEtMDItMjMiKQ0KdHQNCmBgYA0KDQojIEVEQQ0KDQpgYGB7cn0NCmVtcGxveWVkIDwtIHR0JGVtcGxveWVkDQplbXBsb3llZA0KYGBgDQoNCmBgYHtyfQ0Kc3RyKGVtcGxveWVkKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeShlbXBsb3llZCkNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgbXV0YXRlX2lmKGlzLmNoYXJhY3RlciwgYXMuZmFjdG9yKSAlPiUgDQogIHN1bW1hcnkoKQ0KYGBgDQoNCmxvb2tzIGxpa2Ugd2UgaGF2ZSBOQSdzIGluIGRhdGENCg0KIyMgTWlzc2luZyBWYWx1ZXMNCg0KYGBge3J9DQpzYXBwbHkoZW1wbG95ZWQsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpICU+JSANCiAgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KG5hbmlhcikNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgbmFuaWFyOjpnZ19taXNzX3Vwc2V0KCkNCmBgYA0KDQojIyBDb2xzIEZyZXENCg0KYGBge3J9DQp0YWJsZShlbXBsb3llZCRpbmR1c3RyeSkgJT4lIA0KICBhcy5kYXRhLmZyYW1lKCkgJT4lIA0KICBhcnJhbmdlKGRlc2MoRnJlcSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoRnJlcSwgZmN0X3Jlb3JkZXIoVmFyMSwgRnJlcSksIGZpbGwgPSBWYXIxKSkgICsNCiAgZ2VvbV9jb2woKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQpgYGB7cn0NCnRvcF9mcmVxX2VsZW1lbnRzIDwtIGZ1bmN0aW9uKHgpew0KICANCiAgdGFibGUoeCkgJT4lIA0KICAgIGFzLmRhdGEuZnJhbWUoKSAlPiUgDQogICAgYXJyYW5nZShkZXNjKEZyZXEpKSAlPiUgDQogICAgDQogICAgZ2dwbG90KGFlcyhGcmVxLCBmY3RfcmVvcmRlcih4LCBGcmVxKSwgZmlsbCA9IHgpKSAgKw0KICAgIGdlb21fY29sKCkgKw0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCn0NCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgc2VsZWN0X2lmKGlzLmNoYXJhY3RlcikgJT4lIA0KICBtYXAoLiwgLmYgPSB0b3BfZnJlcV9lbGVtZW50cykNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgY291bnQoeWVhcikNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgY291bnQoaW5kdXN0cnkpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IGluZHVzdHJ5LCBmaWxsID0gaW5kdXN0cnkpKSArDQogIGdlb21fY29sKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCg0KZnJvbTogb25lbm90ZTovLy9cXFZJTlktUENcVXNlcnNcdmlueVxEb2N1bWVudHNcT25lTm90ZSUyME5vdGVib29rc1xSJTIwTGVhcm5pbmclMjAmJTIwTm90ZXNcUiUyMFZpc3VhbGl6YXRpb24ub25lI2NvdW50KCklMjAlMjBwbG90JTIwZnJlcXVlbmN5JTIwb2YlMjBlYWNoJTIwdmFyaWFibGUlMjBpbiUyMGElMjBmdW5jdGlvbiZzZWN0aW9uLWlkPXtDMjQ1RDE4My0yRDcxLTQ2RDEtQkNCRS0yQzFBMDQ3QzIyMEJ9JnBhZ2UtaWQ9e0ZFQjFGNzIzLUQ4QjgtNERCOC05QkEzLUFDRDhERjk2RjQ1NH0mb2JqZWN0LWlkPXtBNDZDREYzNS0xRjRELTQ1RTMtQTYzQi1BODlEQzQwMjAzOUF9JjEwDQoNCmBgYHtyfQ0KdmFyX2ZyZXFfcGxvdF9mbiA8LSBmdW5jdGlvbihkZiwgc2VsZWN0ZWRfdmFyKXsNCiAgZGYgJT4lIA0KICAgICMgc2VsZWN0X2lmKGlzLmNoYXJhY3RlcikgJT4lDQogICAgY291bnQoLmRhdGFbW3NlbGVjdGVkX3Zhcl1dKSAlPiUNCiAgICAjIGFzX3RpYmJsZSgpICU+JQ0KICAgIA0KICAgIGdncGxvdChhZXMoeCA9IG4sIHkgPSAuZGF0YVtbc2VsZWN0ZWRfdmFyXV0sIGZpbGwgPSAuZGF0YVtbc2VsZWN0ZWRfdmFyXV0pKSArDQogICAgZ2VvbV9jb2woKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KcHVycnI6Om1hcCgueCA9IG5hbWVzKGVtcGxveWVkICU+JSBzZWxlY3RfaWYoaXMuY2hhcmFjdGVyKSksIA0KICAgICAgICAgICAuZiA9IHZhcl9mcmVxX3Bsb3RfZm4sIA0KICAgICAgICAgICBkZiA9IGVtcGxveWVkKQ0KYGBgDQoNCmBgYHtyfQ0KdmFyX2ZyZXFfcGxvdF9mbiA8LSBmdW5jdGlvbihkZil7DQogIHB1cnJyOjptYXAoZGYgJT4lIA0KICAgICAgICAgICAgICAgc2VsZWN0X2lmKGlzLmNoYXJhY3RlcikgJT4lIA0KICAgICAgICAgICAgICAgbmFtZXMsIH4NCiAgZGYgJT4lIA0KICAgIGNvdW50KC5kYXRhW1sueF1dKSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gLmRhdGFbWy54XV0sIGZpbGwgPSAuZGF0YVtbLnhdXSkpICsNCiAgICBnZW9tX2NvbCgpICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KdmFyX2ZyZXFfcGxvdF9mbihkZiA9IGVtcGxveWVkKQ0KYGBgDQoNCg0KIyMgc2Fua2V5IGhpZ2hjaGFydGVyDQoNCmZyb206IGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ay1JTjZIQmhncTQmdD0xNDJzDQoNCmBgYHtyfQ0KbGlicmFyeShoaWdoY2hhcnRlcikNCmBgYA0KDQpgYGB7ciBmaWcud2lkdGg9IDEwLGZpZy5oZWlnaHQ9MTJ9DQpoaWdoY2hhcnRlcjo6ZGF0YV90b19zYW5rZXkoZGF0YSA9IChlbXBsb3llZCAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdChpbmR1c3RyeSwgbWFqb3Jfb2NjdXBhdGlvbikpKSAlPiUgDQogIGhjaGFydCguLCAic2Fua2V5IiwgbmFtZSA9ICJJbmR1c3RyaWVzIHRvIE9jY3VwYXRpb24iKQ0KYGBgDQoNCmBgYHtyIGZpZy53aWR0aD0gMTAsZmlnLmhlaWdodD0xMn0NCmhpZ2hjaGFydGVyOjpkYXRhX3RvX3NhbmtleShkYXRhID0gKGVtcGxveWVkICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KG1ham9yX29jY3VwYXRpb24sIG1pbm9yX29jY3VwYXRpb24pKSkgJT4lIA0KICBoY2hhcnQoLiwgInNhbmtleSIsIG5hbWUgPSAiTWFqb3Igb2NjdXBhdGlvbiB0byBtaW5vciBvY2N1cGF0aW9uIikgJT4lIA0KICBoY19hZGRfdGhlbWUoaGNfdGhlbWVfbW9ub2thaSgpKSAlPiUgDQogIGhjX3RpdGxlKHRleHQgPSAiSW5kdXN0cnkgdG8gT2NjdXBhdGlvbiBzYW5rZXkgcGxvdCIpDQpgYGANCg0KIyMgRW1wbG95bWVudCBDaGFuZ2UNCg0KYGBge3J9DQplbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveW1lbnRfeXJ3aXNlID0gc3VtKGVtcGxveV9uKSkNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoZW1wbG95bWVudF95cndpc2UgPSBzdW0oZW1wbG95X24pKSAlPiUgDQogIG11dGF0ZShlbXBsb3lfY2hhbmdlID0gKGVtcGxveW1lbnRfeXJ3aXNlIC0gbGFnKGVtcGxveW1lbnRfeXJ3aXNlLCBkZWZhdWx0ID0gMCkpLw0KICAgICAgICAgICBsYWcoZW1wbG95bWVudF95cndpc2UpICkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IHJlcGxhY2UoZW1wbG95X2NoYW5nZSwgaXMubmEoZW1wbG95X2NoYW5nZSksIDApKQ0KYGBgDQoNCg0KYGBge3J9DQplbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgDQogIGdyb3VwX2J5KHllYXIpICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveW1lbnRfeXJ3aXNlID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IChlbXBsb3ltZW50X3lyd2lzZSAtIGxhZyhlbXBsb3ltZW50X3lyd2lzZSwgZGVmYXVsdCA9IDApKS8NCiAgICAgICAgICAgbGFnKGVtcGxveW1lbnRfeXJ3aXNlKSApICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSByZXBsYWNlKGVtcGxveV9jaGFuZ2UsIGlzLm5hKGVtcGxveV9jaGFuZ2UpLCAwKSwNCiAgICAgICAgIGxpbmVfY29sb3IgPSBpZmVsc2UoZW1wbG95X2NoYW5nZSA+PSAwLCAiYmx1ZSIsInJlZCIpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X2NoYW5nZSwgDQogICAgICAgICAgICAgbGFiZWwgPSByb3VuZChlbXBsb3lfY2hhbmdlKjEwMCwgZGlnaXRzID0gMikNCiAgICAgICAgICAgICAsY29sID0gbGluZV9jb2xvcg0KICAgICAgICAgICAgICkpICsNCiAgZ2VvbV9saW5lKGdyb3VwPTEpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwNCiAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoLTAuMDgsIDAuMDIpICkgKw0KICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsNCiAgZ2VvbV90ZXh0KG51ZGdlX3kgPSAuMDA1KSArDQogIGxhYnModGl0bGUgPSAiWWVhcmx5ICUgQ2hhbmdlIGluIEVtcGxveW1lbnQiKQ0KYGBgDQoNCmZyb206IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQ0OTQ3ODA2L2hvdy1jYW4taS1maWxsLXRoZS1zcGFjZS1iZXR3ZWVuLXZhbHVlc2dlb20tbGluZS1hbmQtYW4taW50ZXJjZXB0LXdpdGgtZ2dwbG90Mi80NDk0ODYzMSM0NDk0ODYzMQ0KDQpgYGB7cn0NCmVtcGxveW1lbnRfeXJfY2hhbmdlIDwtIGVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZ3JvdXBfYnkoeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoZW1wbG95bWVudF95cndpc2UgPSBzdW0oZW1wbG95X24pKSAlPiUgDQogIG11dGF0ZShlbXBsb3lfY2hhbmdlID0gKGVtcGxveW1lbnRfeXJ3aXNlIC0gbGFnKGVtcGxveW1lbnRfeXJ3aXNlLCBkZWZhdWx0ID0gMCkpLw0KICAgICAgICAgICBsYWcoZW1wbG95bWVudF95cndpc2UpICkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IHJlcGxhY2UoZW1wbG95X2NoYW5nZSwgaXMubmEoZW1wbG95X2NoYW5nZSksIDApKSAgDQogIA0KICANCmVtcGxveW1lbnRfeXJfY2hhbmdlICU+JSANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveV9jaGFuZ2UsIA0KICAgICAgICAgICAgIGxhYmVsID0gcm91bmQoZW1wbG95X2NoYW5nZSoxMDAsIGRpZ2l0cyA9IDIpDQogICAgICAgICAgICAgIyAsY29sID0gbGluZV9jb2xvcg0KICAgICAgICAgICAgICkpICsNCiAgIyBnZW9tX2xpbmUoZ3JvdXA9MSkgKw0KICAjIGdlb21fcG9pbnQoKSArDQogIGdlb21fcmliYm9uKGFlcyh5bWluPXBtaW4oZW1wbG95bWVudF95cl9jaGFuZ2UkZW1wbG95X2NoYW5nZSwwKSwgeW1heD0wKSwgZmlsbD0icmVkIiwgY29sPSJyZWQiLCBhbHBoYT0wLjUpICsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW49MCwgeW1heD1wbWF4KGVtcGxveW1lbnRfeXJfY2hhbmdlJGVtcGxveV9jaGFuZ2UsMCkpLCBmaWxsPSJncmVlbiIsIGNvbD0iZ3JlZW4iLCBhbHBoYT0wLjUpICsNCiAgDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKC0wLjA4LCAwLjAyKSApICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCJyZWQiKSkgKw0KICBnZW9tX3RleHQobnVkZ2VfeSA9IC4wMDUpICsNCiAgbGFicyh0aXRsZSA9ICJZZWFybHkgJSBDaGFuZ2UgaW4gRW1wbG95bWVudCIpDQpgYGANCg0KIyMjIGRpc3RpbmN0IGNvbG9yIGxpbmUNCg0KQ29sb3JpbmcgcG9zaXRpdmUgJiBuZWdhdGl2ZSBsaW5lIHdpdGggc2VwYXJhdGUgY29sb3JzDQoNCmZyb206IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzY2MzcwNTEzL2hvdy10by1jb2xvci1nZW9tLWxpbmUtZ2VvbS1wb2ludC1wcm9wZXJseS1iYXNlZC1vbi1jb25kaXRpb24taWYtbGVzcy10aGFuLzY2MzcxNzQ2IzY2MzcxNzQ2DQoNCmNyZWF0ZSBmdW5jdGlvbg0KDQpgYGB7cn0NCmRpdmlkZV9saW5lIDwtIGZ1bmN0aW9uKHgsIHksIGF0ID0gMCkgew0KICBkZiA8LSBkYXRhLmZyYW1lKHgsIHltaW4gPSBhdCwgeW1heCA9IHkpDQogIGRmJHNpZ24gPC0gc2lnbihkZiR5bWF4IC0gZGYkeW1pbikNCiAgZGYgPC0gZGZbb3JkZXIoZGYkeCksIF0NCiAgZGYkaWQgPC0gd2l0aChybGUoZGYkc2lnbiksIHJlcC5pbnQoc2VxX2Fsb25nKHZhbHVlcyksIGxlbmd0aHMpKQ0KICANCiAgY3Jvc3NvdmVyIDwtIHdoaWNoKGMoRkFMU0UsIGRpZmYoZGYkaWQpID09IDEpKQ0KICBjcm9zc292ZXIgPC0gc29ydChjKGNyb3Nzb3ZlciwgY3Jvc3NvdmVyIC0gMSkpDQogIHNwbGl0dGVyICA8LSByZXAoc2VxX2xlbihsZW5ndGgoY3Jvc3NvdmVyKSAvIDIpLCBlYWNoID0gMikNCiAgY3Jvc3NvdmVyIDwtIGxhcHBseShzcGxpdChkZltjcm9zc292ZXIsIF0sIHNwbGl0dGVyKSwgZmluZF9pc2VjdCkNCiAgDQogIGRmIDwtIGRvLmNhbGwocmJpbmQsIGMobGlzdChkZiksIGNyb3Nzb3ZlcikpDQogIGRmW29yZGVyKGRmJHgpLF0NCn0NCmZpbmRfaXNlY3QgPC0gZnVuY3Rpb24oZGYpIHsNCiAgbGlzdDJlbnYoZGYsIGVudmlyID0gcmxhbmc6OmN1cnJlbnRfZW52KCkpDQogIGR4IDwtIHhbMV0gLSB4WzJdDQogIGR5IDwtIHltaW5bMV0gLSB5bWluWzJdDQogIHQgPC0gKC0xICogKHltaW5bMV0gLSB5bWF4WzFdKSAqIGR4KSAvIChkeCAqICh5bWF4WzFdIC0geW1heFsyXSkgLSBkeSAqIGR4KQ0KICBkZiR4IDwtIHhbMV0gKyB0ICogLWR4DQogIGRmJHltaW4gPC0gZGYkeW1heCA8LSB5bWluWzFdICsgdCAqIC1keQ0KICByZXR1cm4oZGYpDQp9DQpgYGANCg0KY3JlYXRlIGRmDQoNCmBgYHtyfQ0KZGYgPC0gZGl2aWRlX2xpbmUoZW1wbG95bWVudF95cl9jaGFuZ2UkeWVhciwgZW1wbG95bWVudF95cl9jaGFuZ2UkZW1wbG95X2NoYW5nZSwgYXQgPSAwKQ0KDQpkZg0KYGBgDQoNCmNyZWF0ZSBwbG90DQoNCmBgYHtyfQ0KZ2dwbG90KGRmLCBhZXMoeCwgeW1heCwgZ3JvdXAgPSBpZCwgY29sb3VyID0gYXMuZmFjdG9yKHNpZ24pLA0KICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAocm91bmQoeW1heCoxMDAsIGRpZ2l0cyA9IDIpLCIlIikgKQ0KICAgICAgICkrDQogIGdlb21fbGluZShzaXplID0gLjkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCksIA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtLjA4LC4wMikNCiAgICAgICAgICAgICAgICAgICAgICkgKw0KICBnZW9tX3RleHQobnVkZ2VfeSA9IC4wMDUpICsNCiAgbGFicyh0aXRsZSA9ICJZZWFybHkgJSBDaGFuZ2UgaW4gRW1wbG95bWVudCIpDQpgYGANCg0KDQpgYGB7cn0NCmdncGxvdChkZiwgYWVzKHgsIHltYXgsIGdyb3VwID0gaWQsIGNvbG91ciA9IGFzLmZhY3RvcihzaWduKSwNCiAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKHJvdW5kKHltYXgqMTAwLCBkaWdpdHMgPSAyKSwiJSIpICkNCiAgICAgICApKw0KICBnZW9tX2xpbmUoc2l6ZSA9IC45LCBhZXMobGluZXR5cGUgPSBhcy5mYWN0b3IoaWQpKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzPWMoMiwgMSwgMykpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCksIA0KICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygtLjA4LC4wMikNCiAgICAgICAgICAgICAgICAgICAgICkgKw0KICBnZW9tX3RleHQobnVkZ2VfeSA9IC4wMDUpICsNCiAgbGFicyh0aXRsZSA9ICJZZWFybHkgJSBDaGFuZ2UgaW4gRW1wbG95bWVudCIpDQpgYGANCg0KDQojIyBFbXAgY29tcGFyaXNvbiBjaGFydHMNCg0KYmFsbG9vbiBwbG90IGZyb206IGh0dHA6Ly93d3cuc3RoZGEuY29tL2VuZ2xpc2gvYXJ0aWNsZXMvMzItci1ncmFwaGljcy1lc3NlbnRpYWxzLzEyOS12aXN1YWxpemluZy1tdWx0aXZhcmlhdGUtY2F0ZWdvcmljYWwtZGF0YS8NCg0KaHR0cHM6Ly9ycGtncy5kYXRhbm92aWEuY29tL2dncHVici9yZWZlcmVuY2UvZ2diYWxsb29ucGxvdC5odG1sDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KHZpcmlkaXMpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCxmaWcud2lkdGg9OH0NCmdncHVicjo6Z2diYWxsb29ucGxvdChlbXBsb3llZCwgeCA9ICJtYWpvcl9vY2N1cGF0aW9uIiwgeSA9ICJpbmR1c3RyeSIsIA0KICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAiZW1wbG95X24iLCBmaWxsID0gImVtcGxveV9uIikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiQyIpDQpgYGANCg0KcmVtb3ZpbmcgaXJyZWxldmFudCBjYXRlZ29yaWVzIGZyb20gaW5kdXN0cmllcw0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsZmlnLndpZHRoPTh9DQpnZ3B1YnI6OmdnYmFsbG9vbnBsb3QoZW1wbG95ZWQgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighaW5kdXN0cnkgJWluJSBjKE5BLCAiTWVuIiwiV29tZW4iLCJXaGl0ZSIsIkJsYWNrIG9yIEFmcmljYW4gQW1lcmljYW4iLCAiQXNpYW4iKSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG1ham9yX29jY3VwYXRpb24gPSBzdHJfd3JhcChtYWpvcl9vY2N1cGF0aW9uLCB3aWR0aCA9IDI1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmR1c3RyeSA9IHN0cl93cmFwKGluZHVzdHJ5LCB3aWR0aCA9IDI1KSksIA0KICAgICAgICAgICAgICAgICAgICAgIHggPSAibWFqb3Jfb2NjdXBhdGlvbiIsIHkgPSAiaW5kdXN0cnkiLCANCiAgICAgICAgICAgICAgICAgICAgICBzaXplID0gImVtcGxveV9uIiwgc2hhcGUgPSAxNikgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiQyIpICsNCiAgbGFicyh0aXRsZSA9ICJJbmR1c3RyeSB3aXNlIEVtcGxveW1lbnQgQ29tcGFyaXNvbiIpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD04LGZpZy53aWR0aD04fQ0KZ2dwdWJyOjpnZ2JhbGxvb25wbG90KGVtcGxveWVkICU+JSANCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoIWluZHVzdHJ5ICVpbiUgYyhOQSwgIk1lbiIsIldvbWVuIiwiV2hpdGUiLCJCbGFjayBvciBBZnJpY2FuIEFtZXJpY2FuIiwgIkFzaWFuIikpICU+JSAgDQogICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoaW5kdXN0cnkgPSBzdHJfd3JhcChpbmR1c3RyeSwgd2lkdGggPSAyNSkpLCANCiAgICAgICAgICAgICAgICAgICAgICB4ID0gInllYXIiLCB5ID0gImluZHVzdHJ5IiwgDQogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9ICJlbXBsb3lfbiIsIGZpbGwgPSAiZW1wbG95X24iKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKw0KICBsYWJzKHRpdGxlID0gIkluZHVzdHJ5IEVtcGxveW1lbnQgQ29tcGFyaXNvbiB5ZWFyIHdpc2UiKQ0KYGBgDQoNCg0KYGBge3IgZmlnLmhlaWdodD0xMixmaWcud2lkdGg9MTB9DQpnZ3B1YnI6OmdnYmFsbG9vbnBsb3QoZW1wbG95ZWQgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcighaW5kdXN0cnkgJWluJSBjKE5BLCAiTWVuIiwiV29tZW4iLCJXaGl0ZSIsIkJsYWNrIG9yIEFmcmljYW4gQW1lcmljYW4iLCAiQXNpYW4iKSksIA0KICAgICAgICAgICAgICAgICAgICAgIHggPSAibWFqb3Jfb2NjdXBhdGlvbiIsIHkgPSAiaW5kdXN0cnkiLCANCiAgICAgICAgICAgICAgICAgICAgICBzaXplID0gImVtcGxveV9uIiwgZmlsbCA9ICJlbXBsb3lfbiIsICBzaGFwZSA9IDIxLCANCiAgICAgICAgICAgICAgICAgICAgICBmYWNldC5ieSA9ICJ5ZWFyIiwgZ2d0aGVtZSA9IHRoZW1lX2J3KCkpICsNCiAgDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKw0KICAjIGdyYWRpZW50X2ZpbGwoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkNCiAgDQogIGxhYnModGl0bGUgPSAiWWVhcmx5IEluZHVzdHJ5ICYgb2NjdXBhdGlvbiB3aXNlIGVtcGxveW1lbnQgY29tcGFyaXNvbiIpDQpgYGANCg0KYGBge3J9DQplbXBsb3llZCRtaW5vcl9vY2N1cGF0aW9uICU+JSB1bmlxdWUoKQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsZmlnLndpZHRoPTh9DQpnZ3B1YnI6OmdnYmFsbG9vbnBsb3QoZW1wbG95ZWQsIHggPSAibWFqb3Jfb2NjdXBhdGlvbiIsIHkgPSAibWlub3Jfb2NjdXBhdGlvbiIsIA0KICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAiZW1wbG95X24iLCBmaWxsID0gImVtcGxveV9uIiwgIHNoYXBlID0gMjEsIA0KICAgICAgICAgICAgICAgICAgICAgIGZhY2V0LmJ5ID0gInllYXIiLCBnZ3RoZW1lID0gdGhlbWVfYncoKSkgKw0KICANCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gIkMiKSArDQogICMgZ3JhZGllbnRfZmlsbChjKCJibHVlIiwgIndoaXRlIiwgInJlZCIpKQ0KICANCiAgbGFicyh0aXRsZSA9ICJZZWFybHkgb2NjdXBhdGlvbiB3aXNlIGVtcGxveW1lbnQgY29tcGFyaXNvbiIpDQpgYGANCg0KQXMgd2UgY2FuIHNlZSBpbiBhYm92ZSBjaGFydCB0aGVyZSBhcmUgdHdvIE1hbmFnZW1lbnQsIE1hbmFnZS1tZW50ICYgbmVlZHMgZGF0YSBjbGVhbmluZyBhbmQgcmUgcGxvdHRpbmcNCg0KYGBge3J9DQplbXBsb3llZCA8LSBlbXBsb3llZCAlPiUgDQogIG11dGF0ZShtaW5vcl9vY2N1cGF0aW9uID0gc3RyX3JlcGxhY2UoZW1wbG95ZWQkbWlub3Jfb2NjdXBhdGlvbiwgIk1hbmFnZS1tZW50IiwgIk1hbmFnZW1lbnQiKSkgDQoNCmVtcGxveWVkJG1pbm9yX29jY3VwYXRpb24gJT4lIHVuaXF1ZSgpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD0xMCxmaWcud2lkdGg9OH0NCmdncHVicjo6Z2diYWxsb29ucGxvdChlbXBsb3llZCwgeCA9ICJtYWpvcl9vY2N1cGF0aW9uIiwgeSA9ICJtaW5vcl9vY2N1cGF0aW9uIiwgDQogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9ICJlbXBsb3lfbiIsIGZpbGwgPSAiZW1wbG95X24iLCAgc2hhcGUgPSAyMSwgDQogICAgICAgICAgICAgICAgICAgICAgZmFjZXQuYnkgPSAieWVhciIsIGdndGhlbWUgPSB0aGVtZV9idygpKSArDQogIA0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAiQyIpICsNCiAgIyBncmFkaWVudF9maWxsKGMoImJsdWUiLCAid2hpdGUiLCAicmVkIikpDQogIA0KICBsYWJzKHRpdGxlID0gIlllYXJseSBvY2N1cGF0aW9uIHdpc2UgZW1wbG95bWVudCBjb21wYXJpc29uIikNCmBgYA0KDQoNCiMjIEFkZGluZyBkaW1lbnNpb24NCg0KYGBge3J9DQplbXBsb3llZCA8LSBlbXBsb3llZCAlPiUgDQogIG11dGF0ZShkaW1lbnNpb24gPSBjYXNlX3doZW4ocmFjZV9nZW5kZXIgPT0gIlRPVEFMIiB+ICJUb3RhbCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFjZV9nZW5kZXIgJWluJSBjKCJNZW4iLCAiV29tZW4iKSB+ICJHZW5kZXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiUmFjZSIpKSANCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgc2VsZWN0KGRpbWVuc2lvbikgJT4lIA0KICB0YWJsZSgpDQpgYGANCg0KIyMgSW5kdXN0cnkgRW1wIENvbXBhcmlzb24NCg0KYGBge3J9DQplbXBsb3llZF9pbmRfY2xlYW5lZCA8LSBlbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIlRvdGFsIikgJT4lIA0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfbHVtcChpbmR1c3RyeSwgMTEsIHcgPSBlbXBsb3lfbiksDQogICAgICAgICBpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBlbXBsb3lfbiwgc3VtKSkNCmBgYA0KDQojIyMgSW5kdXN0cnkgU3RhY2sgcGxvdA0KDQpgYGB7cn0NCmVtcGxveWVkX2luZF9jbGVhbmVkICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgZmlsbCA9IGluZHVzdHJ5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpICsNCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgZW1wbG95cyBpbmR1c3RyeSB3aXNlIGFjcm9zcyB0aGUgeWVhcnMiKSArDQogIHNjYWxlX2ZpbGxfcGFuZGVyKCkNCmBgYA0KDQojIyMgSW5kdXN0cnkgY2lyY3VsYXIgYmFyDQoNCmBgYHtyfQ0KZW1wbG95ZWRfaW5kX2NsZWFuZWQgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDIwKSAlPiUgDQogICMgc3VtbWFyaXNlKG1heChlbXBsb3lfbikpDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBpbmR1c3RyeSwgeSA9IGVtcGxveV9uLCBmaWxsID0gaW5kdXN0cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogICMgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIHlsaW0oMCwyNTAwMDAwMCkgKw0KICBjb29yZF9wb2xhcihzdGFydCA9IDApICsNCiAgbGFicyh0aXRsZSA9ICJOdW1iZXIgb2YgZW1wbG95cyBpbmR1c3RyeSB3aXNlIGluIDIwMjAiKQ0KYGBgDQoNCmBgYHtyfQ0KZW1wbG95ZWRfaW5kX2NsZWFuZWQgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSAyMDIwKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmVvcmRlcihpbmR1c3RyeSwgZW1wbG95X24sIHN1bSksIHkgPSBlbXBsb3lfbiwgZmlsbCA9IGluZHVzdHJ5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgIyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSwNCiAgIyAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gLTUwLDIwMDAwMDAwKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICB5bGltKC01MDAwMDAwLDI1MDAwMDAwKSArDQogIGNvb3JkX3BvbGFyKHN0YXJ0ID0gMjQwKSArDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGVtcGxveXMgaW5kdXN0cnkgd2lzZSBpbiAyMDIwIikNCmBgYA0KDQoNCiMjIyBJbmR1c3RyeSBmYWNldA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KZW1wbG95ZWRfaW5kX2NsZWFuZWQgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveV9uLCBmaWxsID0gaW5kdXN0cnkpKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04LCBmYWNlID0gImJvbGQiKSkgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluZHVzdHJ5IHdpc2UgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiS2VlcGluZyBzY2FsZSBmaXhlZCBmb3IgaW5kdXN0cnkgbGV2ZWwgY29tcGFyaXNvbiIpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIHNjYWxlX2ZpbGxfcGFuZGVyKCkNCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X24sIGZpbGwgPSBpbmR1c3RyeSkpICsNCiAgZ2VvbV9jb2woKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2UgPSAiYm9sZCIpKSArDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGVtcGxveXMgaW5kdXN0cnkgd2lzZSBhY3Jvc3MgdGhlIHllYXJzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJGcmVlIHNjYWxlIGNvbXBhcmlzb24iKSArDQogIGZhY2V0X3dyYXAofiBpbmR1c3RyeSwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgc2NhbGVfZmlsbF9wYW5kZXIoKSANCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQoNCmVtcGxveWVkX2luZF9jbGVhbmVkICU+JSANCiAgZ3JvdXBfYnkoaW5kdXN0cnksIHllYXIpICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveW1lbnRfeXJ3aXNlID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IChlbXBsb3ltZW50X3lyd2lzZSAtIGxhZyhlbXBsb3ltZW50X3lyd2lzZSwgZGVmYXVsdCA9IDApKSwNCiAgICAgICAgIGluZHVzdHJ5ID0gc3RyX3dyYXAoaW5kdXN0cnksIHdpZHRoID0gMjApKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X2NoYW5nZSwgY29sID0gaW5kdXN0cnkpKSArDQogIGdlb21fbGluZShzaXplID0gLjkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTQwMDAwMDAsMjAwMDAwMCksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIGZhY2V0X3dyYXAofiBpbmR1c3RyeSkgKw0KICANCiAgbGFicyh0aXRsZSA9ICJZZWFybHkgQWN0dWFsIENoYW5nZSBpbiBlbXBsb3ltZW50IGNvdW50IEluZHVzdHJ5IHdpc2UiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2UgPSAiYm9sZCIpKSArDQogIGd1aWRlcyh4ID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMykpDQpgYGANCg0KDQojIyMgSW5kdXN0cnkgJSBjaGFuZ2UNCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCg0KZW1wbG95ZWRfaW5kX2NsZWFuZWQgJT4lIA0KICBncm91cF9ieShpbmR1c3RyeSwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoZW1wbG95bWVudF95cndpc2UgPSBzdW0oZW1wbG95X24pKSAlPiUgDQogIG11dGF0ZShlbXBsb3lfY2hhbmdlID0gKGVtcGxveW1lbnRfeXJ3aXNlIC0gbGFnKGVtcGxveW1lbnRfeXJ3aXNlLCBkZWZhdWx0ID0gMCkpLw0KICAgICAgICAgICBsYWcoZW1wbG95bWVudF95cndpc2UpLA0KICAgICAgICAgaW5kdXN0cnkgPSBzdHJfd3JhcChpbmR1c3RyeSwgd2lkdGggPSAyMCkgKSAlPiUgDQogIG11dGF0ZShlbXBsb3lfY2hhbmdlID0gcmVwbGFjZShlbXBsb3lfY2hhbmdlLCBpcy5uYShlbXBsb3lfY2hhbmdlKSwgMCkgJT4lIHJvdW5kKGRpZ2l0cyA9IDQpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X2NoYW5nZSwgZmlsbCA9IGluZHVzdHJ5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIA0KICBsYWJzKHRpdGxlID0gIlllYXJseSAlIENoYW5nZSBpbiBlbXBsb3ltZW50IGNvdW50IEluZHVzdHJ5IHdpc2UiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2UgPSAiYm9sZCIpKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dzYXZlKCJlbXBfY2hhbmdlX2luZHVzdHJ5LmpwZyIpDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIGdyb3VwX2J5KGluZHVzdHJ5LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3ltZW50X3lyd2lzZSA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSAoZW1wbG95bWVudF95cndpc2UgLSBsYWcoZW1wbG95bWVudF95cndpc2UsIGRlZmF1bHQgPSAwKSkvDQogICAgICAgICAgIGxhZyhlbXBsb3ltZW50X3lyd2lzZSksDQogICAgICAgICBpbmR1c3RyeSA9IHN0cl93cmFwKGluZHVzdHJ5LCB3aWR0aCA9IDIwKSApICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSByZXBsYWNlKGVtcGxveV9jaGFuZ2UsIGlzLm5hKGVtcGxveV9jaGFuZ2UpLCAwKSAlPiUgcm91bmQoZGlnaXRzID0gNCkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfY2hhbmdlLCBmaWxsID0gaW5kdXN0cnkpKSArDQogIGdlb21fY29sKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICBmYWNldF93cmFwKH4gaW5kdXN0cnkpICsNCiAgDQogIGxhYnModGl0bGUgPSAiWWVhcmx5ICUgQ2hhbmdlIGluIGVtcGxveW1lbnQgY291bnQgSW5kdXN0cnkgd2lzZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCwgZmFjZSA9ICJib2xkIikpDQpgYGANCg0KDQpgYGB7cn0NCmdnc2F2ZSgiZW1wX2NoYW5nZV9pbmR1c3RyeV9mbGlwcGVkLmpwZyIpDQpgYGANCg0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQoNCmVtcGxveWVkX2luZF9jbGVhbmVkICU+JSANCiAgZ3JvdXBfYnkoaW5kdXN0cnksIHllYXIpICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveW1lbnRfeXJ3aXNlID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IChlbXBsb3ltZW50X3lyd2lzZSAtIGxhZyhlbXBsb3ltZW50X3lyd2lzZSwgZGVmYXVsdCA9IDApKS8NCiAgICAgICAgICAgbGFnKGVtcGxveW1lbnRfeXJ3aXNlKSwNCiAgICAgICAgIGluZHVzdHJ5ID0gc3RyX3dyYXAoaW5kdXN0cnksIHdpZHRoID0gMjApICkgJT4lIA0KICBtdXRhdGUoZW1wbG95X2NoYW5nZSA9IHJlcGxhY2UoZW1wbG95X2NoYW5nZSwgaXMubmEoZW1wbG95X2NoYW5nZSksIDApICU+JSByb3VuZChkaWdpdHMgPSA0KSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveV9jaGFuZ2UsIGNvbCA9IGluZHVzdHJ5KSkgKw0KICBnZW9tX2xpbmUoc2l6ZT0uOSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICBmYWNldF93cmFwKH4gaW5kdXN0cnkpICsNCiAgDQogIGxhYnModGl0bGUgPSAiWWVhcmx5ICUgQ2hhbmdlIGluIGVtcGxveW1lbnQgY291bnQgSW5kdXN0cnkgd2lzZSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCANCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkNCmBgYA0KDQpmcm9tOiBodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PV83SjZCYkRncXJBDQoNCmJ1dCBpcyBub3Qgd29ya2luZyBhcyBleHBlY3RlZA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIGdyb3VwX2J5KGluZHVzdHJ5LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3ltZW50X3lyd2lzZSA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSAoZW1wbG95bWVudF95cndpc2UgLSBsYWcoZW1wbG95bWVudF95cndpc2UsIGRlZmF1bHQgPSAwKSkvDQogICAgICAgICAgIGxhZyhlbXBsb3ltZW50X3lyd2lzZSksDQogICAgICAgICBpbmR1c3RyeSA9IHN0cl93cmFwKGluZHVzdHJ5LCB3aWR0aCA9IDIwKSApICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSByZXBsYWNlKGVtcGxveV9jaGFuZ2UsIGlzLm5hKGVtcGxveV9jaGFuZ2UpLCAwKSAlPiUgcm91bmQoZGlnaXRzID0gNCkpICU+JSANCiAgDQogIGdncGxvdCgpICsNCiAgZ2VvbV9jb2woYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X2NoYW5nZSAqIDIwMDAwMDAwLCBmaWxsID0gZW1wbG95X2NoYW5nZSA+IDApLCBhbHBoYSA9IDAuNCkgKw0KICBnZW9tX2xpbmUoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95bWVudF95cndpc2UpLCBncm91cCA9MSkgKw0KICBnZW9tX3BvaW50KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveW1lbnRfeXJ3aXNlLCBjb2wgPSBlbXBsb3lfY2hhbmdlID4gMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIA0KICBsYWJzKHRpdGxlID0gIlllYXJseSAlIENoYW5nZSBpbiBlbXBsb3ltZW50IGNvdW50IEluZHVzdHJ5IHdpc2UiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgsIGZhY2UgPSAiYm9sZCIpKSArDQogIGd1aWRlcyh4ID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMykpDQpgYGANCg0KYnkgYWRkaW5nIGdlb21fdGV4dCB0aGlzIHdvcmtlZA0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIGdyb3VwX2J5KGluZHVzdHJ5LCB5ZWFyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3ltZW50X3lyd2lzZSA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgbXV0YXRlKGVtcGxveV9jaGFuZ2UgPSAoZW1wbG95bWVudF95cndpc2UgLSBsYWcoZW1wbG95bWVudF95cndpc2UpKS8NCiAgICAgICAgICAgbGFnKGVtcGxveW1lbnRfeXJ3aXNlKSApICU+JSANCiAgbmEub21pdCgpICU+JQ0KICBtdXRhdGUoaW5kdXN0cnkgPSBzdHJfd3JhcChpbmR1c3RyeSwgd2lkdGggPSAyMCkpICU+JSANCiAgIA0KICANCiAgZ2dwbG90KCkgKw0KICBnZW9tX2NvbChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfY2hhbmdlICogMjAwMDAwMDAsIGZpbGwgPSBlbXBsb3lfY2hhbmdlID4gMCksIGFscGhhID0gMC40KSArDQogIGdlb21fbGluZShhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3ltZW50X3lyd2lzZSksIGdyb3VwID0xKSArDQogIGdlb21fcG9pbnQoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95bWVudF95cndpc2UsIGNvbCA9IGVtcGxveV9jaGFuZ2UgPiAwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICANCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIGxhYnModGl0bGUgPSAiSW5kdXN0cnkgd2lzZSBZZWFybHkgJSBDaGFuZ2UgJiAjIGluIGVtcGxveW1lbnQiLA0KICAgICAgIHkgPSAiIyBFbXBsb3ltZW50IChpbiBNaWxsaW9ucykiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTgpKSArDQogIGd1aWRlcyh4ID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMikpICsNCiAgDQogIGdlb21fdGV4dChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfY2hhbmdlLCBsYWJlbCA9IHBhc3RlMChyb3VuZChlbXBsb3lfY2hhbmdlKjEwMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cz0xKSwiJSIpDQogICAgICAgICAgICAgICAgLCBjb2wgPSBlbXBsb3lfY2hhbmdlID4gMCksIA0KICAgICAgICAgICAgbnVkZ2VfeSA9IC0zMDAwMDAwLCBzaXplID0gMi4yLCBhbmdsZSA9IDQ1KQ0KYGBgDQoNCmBgYHtyfQ0KZ2dzYXZlKCJhY3R1YWxfcGVyY19jaGFuZ2VfaW5fZW1wLmpwZyIpDQpgYGANCg0KYWRkaW5nIGdlb21fdGV4dCB0byBnZW9tX2xpbmUNCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCg0KZW1wbG95ZWRfaW5kX2NsZWFuZWQgJT4lIA0KICBncm91cF9ieShpbmR1c3RyeSwgeWVhcikgJT4lIA0KICBzdW1tYXJpc2UoZW1wbG95bWVudF95cndpc2UgPSBzdW0oZW1wbG95X24pKSAlPiUgDQogIG11dGF0ZShlbXBsb3lfY2hhbmdlID0gKGVtcGxveW1lbnRfeXJ3aXNlIC0gbGFnKGVtcGxveW1lbnRfeXJ3aXNlKSkvDQogICAgICAgICAgIGxhZyhlbXBsb3ltZW50X3lyd2lzZSkgKSAlPiUgDQogIG5hLm9taXQoKSAlPiUNCiAgbXV0YXRlKGluZHVzdHJ5ID0gc3RyX3dyYXAoaW5kdXN0cnksIHdpZHRoID0gMjApKSAlPiUgDQogIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fY29sKGFlcyh4ID0geWVhciwgeSA9IGVtcGxveV9jaGFuZ2UgKiAyMDAwMDAwMCwgZmlsbCA9IGVtcGxveV9jaGFuZ2UgPiAwKSwgYWxwaGEgPSAwLjQpICsNCiAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwgeSA9IGVtcGxveW1lbnRfeXJ3aXNlKSwgZ3JvdXAgPTEpICsNCiAgZ2VvbV9wb2ludChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3ltZW50X3lyd2lzZSwgY29sID0gZW1wbG95X2NoYW5nZSA+IDApKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIA0KICBmYWNldF93cmFwKH4gaW5kdXN0cnkpICsNCiAgbGFicyh0aXRsZSA9ICJJbmR1c3RyeSB3aXNlIFllYXJseSAlIENoYW5nZSAmICMgaW4gZW1wbG95bWVudCIsDQogICAgICAgeSA9ICIjIEVtcGxveW1lbnQgKGluIE1pbGxpb25zKSIpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCkpICsNCiAgZ3VpZGVzKHggPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAyKSkgKw0KICANCiAgZ2VvbV90ZXh0KGFlcyh4ID0geWVhciwgeSA9IChlbXBsb3lfY2hhbmdlICogMjAwMDAwMDApIC0gMzAwMDAwMCwgDQogICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAocm91bmQoZW1wbG95X2NoYW5nZSoxMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlnaXRzPTEpLCIlIikNCiAgICAgICAgICAgICAgICAsIGNvbCA9IGVtcGxveV9jaGFuZ2UgPiAwKSwgDQogICAgICAgICAgICBzaXplID0gMiwgYW5nbGUgPSA0NSkgKw0KICANCiAgZ2VvbV90ZXh0KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveW1lbnRfeXJ3aXNlICsgNTAwMDAwMCwgDQogICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZShyb3VuZChlbXBsb3ltZW50X3lyd2lzZS8xMDAwMDAwLCBkaWdpdHM9MSksICJNIikNCiAgICAgICAgICAgICAgICAsIGNvbCA9IGVtcGxveV9jaGFuZ2UgPiAwKSwgDQogICAgICAgICAgICBzaXplID0gMiwgYW5nbGUgPSAzNSkNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dzYXZlKCJhY3R1YWxfcGVyY19jaGFuZ2VfaW5fZW1wMi5qcGciKQ0KYGBgDQoNCiMjIE9jY3VwYXRpb24gRW1wIENvbXBhcmlzb24NCg0KIyMjIE1ham9yIE9jY3VwYXRpb24NCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X24sIGZpbGwgPSBtYWpvcl9vY2N1cGF0aW9uKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgIyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIikgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluIE1ham9yIG9jY3VwYXRpb24sIEluZHVzdHJ5IHdpc2UgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiS2VlcGluZyBzY2FsZSBmaXhlZCBmb3IgaW5kdXN0cnkgbGV2ZWwgY29tcGFyaXNvbiIpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KQ0KYGBgDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQoNCmVtcGxveWVkX2luZF9jbGVhbmVkICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgZmlsbCA9IG1ham9yX29jY3VwYXRpb24pKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT03KSkgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluIE1ham9yIG9jY3VwYXRpb24sIEluZHVzdHJ5IHdpc2UgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiS2VlcGluZyBzY2FsZSBmaXhlZCBmb3IgaW5kdXN0cnkgbGV2ZWwgY29tcGFyaXNvbiIpICsNCiAgZmFjZXRfd3JhcCh+IG1ham9yX29jY3VwYXRpb24pDQpgYGANCg0KIyMjIE1pbm9yIG9jY3VwYXRpb24NCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gZW1wbG95X24sIGZpbGwgPSBtaW5vcl9vY2N1cGF0aW9uKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgIyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIikgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluIE1pbm9yIG9jY3VwYXRpb24sIEluZHVzdHJ5IHdpc2UgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiS2VlcGluZyBzY2FsZSBmaXhlZCBmb3IgaW5kdXN0cnkgbGV2ZWwgY29tcGFyaXNvbiIpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KQ0KYGBgDQoNCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIG11dGF0ZShtaW5vcl9vY2N1cGF0aW9uID0gc3RyX3dyYXAobWlub3Jfb2NjdXBhdGlvbiwgd2lkdGggPSAyNSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgZmlsbCA9IG1pbm9yX29jY3VwYXRpb24pKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KSkgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluIE1pbm9yIG9jY3VwYXRpb24sIEluZHVzdHJ5IHdpc2UgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiS2VlcGluZyBzY2FsZSBmaXhlZCBmb3IgaW5kdXN0cnkgbGV2ZWwgY29tcGFyaXNvbiIpICsNCiAgZmFjZXRfd3JhcCh+IG1pbm9yX29jY3VwYXRpb24pDQpgYGANCg0KIyMjIE1ham9yICYgTWlub3INCg0KYGBge3IgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQplbXBsb3llZF9pbmRfY2xlYW5lZCAlPiUgDQogIG11dGF0ZShtYWpvcl9vY2N1cGF0aW9uID0gc3RyX3dyYXAobWFqb3Jfb2NjdXBhdGlvbiwgd2lkdGggPSAzMCkpICU+JQ0KICANCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IGVtcGxveV9uLCBmaWxsID0gbWlub3Jfb2NjdXBhdGlvbikpICsNCiAgZ2VvbV9jb2woKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIHRoZW1lKHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT04KSkgKw0KICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBlbXBsb3lzIGluIE1pbm9yIG9jY3VwYXRpb24sIE1ham9yIG9jY3VwYXRpb24gd2lzZSBhY3Jvc3MgdGhlIHllYXJzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJLZWVwaW5nIHNjYWxlIGZpeGVkIGZvciBpbmR1c3RyeSBsZXZlbCBjb21wYXJpc29uIikgKw0KICBmYWNldF93cmFwKH4gbWFqb3Jfb2NjdXBhdGlvbikNCmBgYA0KDQoNCiMjIEdlbmRlciBJbmR1c3RyeSBDb21wYXJpc29uDQoNCmBgYHtyIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9DQplbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIkdlbmRlciIpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgZmlsbCA9IHJhY2VfZ2VuZGVyKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHVuaXQgPSAiTSIsIHNjYWxlID0gMWUtNikpICsNCiAgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTcpKSArDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGVtcGxveXMgaW5kdXN0cnkgd2lzZSBhY3Jvc3MgdGhlIHllYXJzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJDb2xvcmVkIGJ5IEdlbmRlciIpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIHNjYWxlX2ZpbGxfdGFibGVhdSgpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZmlsdGVyKGRpbWVuc2lvbiA9PSAiR2VuZGVyIikgJT4lIA0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfbHVtcChpbmR1c3RyeSwgMTEsIHcgPSBlbXBsb3lfbikpICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgaW5kdXN0cnksIHJhY2VfZ2VuZGVyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3lfbiA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIGdlb21fbGluZShzaXplID0gMC45KSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGVtcGxveXMgaW5kdXN0cnkgd2lzZSBiYXNlZCBvbiBHZW5kZXIgYWNyb3NzIHRoZSB5ZWFycyIpICsNCiAgZmFjZXRfd3JhcCh+IGluZHVzdHJ5KSArDQogIGd1aWRlcyh4ID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gMykpICsNCiAgc2NhbGVfY29sb3JfdGFibGVhdSgpDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZmlsdGVyKGRpbWVuc2lvbiA9PSAiR2VuZGVyIikgJT4lIA0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfbHVtcChpbmR1c3RyeSwgMTEsIHcgPSBlbXBsb3lfbikpICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgaW5kdXN0cnksIHJhY2VfZ2VuZGVyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3lfbiA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIGdlb21fbGluZShzaXplID0gMC45KSArDQogIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIikgKw0KICBsYWJzKHRpdGxlID0gIkxvZyBvZiBlbXBsb3lzIGluZHVzdHJ5IHdpc2UgYmFzZWQgb24gR2VuZGVyIGFjcm9zcyB0aGUgeWVhcnMiKSArDQogIGZhY2V0X3dyYXAofiBpbmR1c3RyeSkgKw0KICBndWlkZXMoeCA9IGd1aWRlX2F4aXMobi5kb2RnZSA9IDMpKSArDQogIHNjYWxlX2NvbG9yX3RhYmxlYXUoKQ0KYGBgDQoNCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZmlsdGVyKGRpbWVuc2lvbiA9PSAiR2VuZGVyIikgJT4lIA0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfbHVtcChpbmR1c3RyeSwgMTUsIHcgPSBlbXBsb3lfbikpICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgaW5kdXN0cnksIHJhY2VfZ2VuZGVyKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3lfbiA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSBlbXBsb3lfbiwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIGdlb21fbGluZShzaXplID0gMC45KSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSArDQogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIGVtcGxveXMgaW5kdXN0cnkgd2lzZSBiYXNlZCBvbiBHZW5kZXIgYWNyb3NzIHRoZSB5ZWFycyIsDQogICAgICAgc3VidGl0bGUgPSAiKEZyZWUgc2NhbGUgY29tcGFyaXNvbikiKSArDQogIGZhY2V0X3dyYXAofiBpbmR1c3RyeSwgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgZ3VpZGVzKHggPSBndWlkZV9heGlzKG4uZG9kZ2UgPSAzKSkgKw0KICBzY2FsZV9jb2xvcl90YWJsZWF1KGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSkNCmBgYA0KDQojIyAyMDE5LTIwMjAgRW1wbHkgY2hhbmdlDQoNCg0KYGBge3J9DQpjb21wYXJlXzIwMTlfMjAyMCA8LSBlbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgDQogIGZpbHRlcih5ZWFyICVpbiUgYygyMDE5LCAyMDIwKSkgJT4lIA0KICBhcnJhbmdlKHllYXIpICU+JSANCiAgZ3JvdXBfYnkoaW5kdXN0cnksIHllYXIsIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIpICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveV9uID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICANCiAgZ3JvdXBfYnkoaW5kdXN0cnksIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIpICU+JSANCiAgc3VtbWFyaXNlKHJhdGlvID0gbGFzdChlbXBsb3lfbikgLyBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBjaGFuZ2UgPSByYXRpbyAtMSwNCiAgICAgICAgICAgIGVtcGxveWVkXzIwMTkgPSBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBlbXBsb3lfMjAyMCA9IGxhc3QoZW1wbG95X24pKSAlPiUNCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIoaW5kdXN0cnksIGNoYW5nZSwgc3VtKSkgJT4lIA0KICB1bmdyb3VwKCkNCg0KY29tcGFyZV8yMDE5XzIwMjANCmBgYA0KDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQoNCmNvbXBhcmVfMjAxOV8yMDIwICU+JSANCiAgZmlsdGVyKGRpbWVuc2lvbiA9PSAiVG90YWwiKSAlPiUgDQogIG11dGF0ZShpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBpbmR1c3RyeSwgZmlsbCA9IGluZHVzdHJ5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIGxhYnModGl0bGUgPSAiSW5kdXN0cnkgJUNoYW5nZSBpbiBlbXBseS4gZnJvbSAyMDE5IHRvIDIwMjAiLA0KICAgICAgIHkgPSAiIikgDQpgYGANCg0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCg0KY29tcGFyZV8yMDE5XzIwMjAgJT4lIA0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJUb3RhbCIpICU+JSANCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIoaW5kdXN0cnksIGNoYW5nZSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IGNoYW5nZSwgeSA9IGluZHVzdHJ5LCBmaWxsID0gaW5kdXN0cnkpKSArDQogIGdlb21fY29sKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgbGFicyh0aXRsZSA9ICJJbmR1c3RyeSAlQ2hhbmdlIGluIGVtcGx5LiBmcm9tIDIwMTkgdG8gMjAyMCIsDQogICAgICAgeSA9ICIiKSArDQogIGdlb21fbGFiZWwoYWVzKGxhYmVsID0gZW1wbG95XzIwMjApLCBzaXplID0gMywgY29sb3IgPSAid2hpdGUiKQ0KYGBgDQoNCg0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCg0KY29tcGFyZV8yMDE5XzIwMjAgJT4lIA0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJHZW5kZXIiKSAlPiUgDQogIG11dGF0ZShpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBpbmR1c3RyeSwgZmlsbCA9IHJhY2VfZ2VuZGVyKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgc2NhbGVfZmlsbF90YWJsZWF1KCkgKw0KICBsYWJzKHRpdGxlID0gIkluZHVzdHJ5ICVDaGFuZ2UgaW4gZW1wbHkuIGZyb20gMjAxOSB0byAyMDIwIiwNCiAgICAgICB5ID0gIiIpDQpgYGANCg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KDQpjb21wYXJlXzIwMTlfMjAyMCAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIkdlbmRlciIpICU+JSANCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIoaW5kdXN0cnksIGNoYW5nZSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IGNoYW5nZSwgeSA9IGluZHVzdHJ5LCBmaWxsID0gcmFjZV9nZW5kZXIpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLCBsZWdlbmQuZGlyZWN0aW9uID0gInZlcnRpY2FsIikgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICBzY2FsZV9maWxsX3RhYmxlYXUoZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIGxhYnModGl0bGUgPSAiSW5kdXN0cnkgJUNoYW5nZSBpbiBlbXBseS4gZnJvbSAyMDE5IHRvIDIwMjAiLA0KICAgICAgIHkgPSAiIikNCmBgYA0KDQojIyMgbG9sbHlwb3AgcGxvdA0KDQojIyMjIEdlbmRlcg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KDQpjb21wYXJlXzIwMTlfMjAyMCAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIkdlbmRlciIpICU+JSANCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIoaW5kdXN0cnksIGNoYW5nZSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IGNoYW5nZSwgeSA9IGluZHVzdHJ5LCBjb2wgPSByYWNlX2dlbmRlcikpICsNCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gY2hhbmdlKSwgaGVpZ2h0ID0gMCkgKw0KICBnZW9tX3BvaW50KGFlcyhzaXplID0gZW1wbG95ZWRfMjAxOSkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCkpICsNCiAgc2NhbGVfY29sb3JfdGFibGVhdShndWlkZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpICsNCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKGd1aWRlID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICJJbmR1c3RyeSAlQ2hhbmdlIGluIGVtcGx5LiBmcm9tIDIwMTkgdG8gMjAyMCIsDQogICAgICAgeSA9ICIiLCBjb2wgPSAiR2VuZGVyIiwgc2l6ZSA9ICIyMDE5IGVtcGxveSAjIikNCmBgYA0KDQoNCg0KYGBge3IgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0NCg0KY29tcGFyZV8yMDE5XzIwMjAgJT4lIA0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJHZW5kZXIiKSAlPiUgDQogIG11dGF0ZShpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBpbmR1c3RyeSwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIA0KICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbiA9IDAsIHhtYXggPSBjaGFuZ2UpLCBoZWlnaHQgPSAwLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGVtcGxveWVkXzIwMTkpLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgc2l6ZSA9IDEpICsNCiAgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIHNjYWxlX2NvbG9yX3RhYmxlYXUoZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIHNjYWxlX3NpemVfY29udGludW91cyhndWlkZSA9IEZBTFNFKSArDQogIGV4cGFuZF9saW1pdHMoeCA9IC4yKSArDQogIA0KICBsYWJzKHRpdGxlID0gc3RyX3dyYXAoIiUgQ2hhbmdlIGluIEVtcGx5LiBmb3IgSW5kdXN0cmllcyIsIDM1KSwNCiAgICAgICBzdWJ0aXRsZSA9ICIoZnJvbTogMjAxOSB0byAyMDIwKSBcbiBcblNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIGVtcGx5ICMgaW4gMjAxOSBcbiBMb2xseXBvcCBSZXNwcmVzZW50cyBHZW5kZXIiLA0KICAgICAgIGNhcHRpb24gPSAiQ3JlYXRlZCBieSBWaVNhIiwNCiAgICAgICB5ID0gIiIsIHggPSAiQ2hhbmdlIGluIGVtcGxveW1lbnQgZnJvbSAyMDE5LTIwMjAiLA0KICAgICAgIGNvbCA9ICJHZW5kZXIiICkNCmBgYA0KDQpgYGB7cn0NCmdnc2F2ZShmaWxlbmFtZSA9ICJJbmR1c3RyeS1nZW5kZXItbG9seXBvcC5qcGciKQ0KYGBgDQoNCg0KIyMjIyBSYWNlDQoNCmBgYHtyIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD04fQ0KDQpjb21wYXJlXzIwMTlfMjAyMCAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIlJhY2UiKSAlPiUgDQogIG11dGF0ZShpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBpbmR1c3RyeSwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIA0KICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbiA9IDAsIHhtYXggPSBjaGFuZ2UpLCBoZWlnaHQgPSAwLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGVtcGxveWVkXzIwMTkpLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgc2l6ZSA9IDEpICsNCiAgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIHNjYWxlX2NvbG9yX3RhYmxlYXUoZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIHNjYWxlX3NpemVfY29udGludW91cyhndWlkZSA9IEZBTFNFKSArDQogIA0KICBsYWJzKHRpdGxlID0gc3RyX3dyYXAoIiUgQ2hhbmdlIGluIEVtcGx5LiBmb3IgSW5kdXN0cmllcyIsIDM1KSwNCiAgICAgICBzdWJ0aXRsZSA9ICIoZnJvbTogMjAxOSB0byAyMDIwKSBcbiBcblNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIGVtcGx5ICMgaW4gMjAxOSBcbiBMb2xseXBvcCBSZXNwcmVzZW50cyBSYWNlIiwNCiAgICAgICBjYXB0aW9uID0gIkNyZWF0ZWQgYnkgVmlTYSIsDQogICAgICAgeSA9ICIiLCB4ID0gIkNoYW5nZSBpbiBlbXBsb3ltZW50IGZyb20gMjAxOS0yMDIwIiwgDQogICAgICAgY29sID0gIlJhY2UiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dzYXZlKGZpbGVuYW1lID0gIkluZHVzdHJ5LXJhY2UtbG9seXBvcC5qcGciKQ0KYGBgDQoNCiMjIyBtYWpvciBvY2N1cGF0aW9uDQoNCiMjIyMgR2VuZGVyDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQoNCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTksIDIwMjApKSAlPiUgDQogIGFycmFuZ2UoeWVhcikgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBkaW1lbnNpb24sIHJhY2VfZ2VuZGVyLCBtYWpvcl9vY2N1cGF0aW9uKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3lfbiA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgDQogIGdyb3VwX2J5KG1ham9yX29jY3VwYXRpb24sIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIpICU+JSANCiAgc3VtbWFyaXNlKHJhdGlvID0gbGFzdChlbXBsb3lfbikgLyBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBjaGFuZ2UgPSByYXRpbyAtMSwNCiAgICAgICAgICAgIGVtcGxveWVkXzIwMTkgPSBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBlbXBsb3lfMjAyMCA9IGxhc3QoZW1wbG95X24pKSAlPiUNCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIobWFqb3Jfb2NjdXBhdGlvbiwgY2hhbmdlLCBzdW0pKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIA0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJHZW5kZXIiKSAlPiUNCiAgDQogIG11dGF0ZShtYWpvcl9vY2N1cGF0aW9uID0gZmN0X3Jlb3JkZXIobWFqb3Jfb2NjdXBhdGlvbiwgY2hhbmdlKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyh4ID0gY2hhbmdlLCB5ID0gbWFqb3Jfb2NjdXBhdGlvbiwgY29sID0gcmFjZV9nZW5kZXIpKSArDQogIA0KICBnZW9tX2Vycm9yYmFyaChhZXMoeG1pbiA9IDAsIHhtYXggPSBjaGFuZ2UpLCBoZWlnaHQgPSAwLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGVtcGxveWVkXzIwMTkpLA0KICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuNikpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgc2l6ZSA9IDEpICsNCiAgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpLCBsaW1pdHMgPSBjKC0uMiwuMSkpICsNCiAgc2NhbGVfY29sb3JfdGFibGVhdShndWlkZSA9IGd1aWRlX2xlZ2VuZChyZXZlcnNlID0gVFJVRSkpICsNCiAgc2NhbGVfc2l6ZV9jb250aW51b3VzKGd1aWRlID0gRkFMU0UpICsNCiAgDQogIGxhYnModGl0bGUgPSBzdHJfd3JhcCgiJSBDaGFuZ2UgaW4gRW1wbHkuIGJ5IE1ham9yIE9jY3VwYXRpb24iLCAzNSksDQogICAgICAgc3VidGl0bGUgPSAiKGZyb206IDIwMTkgdG8gMjAyMCkgXG4gXG5TaXplIGlzIHByb3BvcnRpb25hbCB0byBlbXBseSAjIGluIDIwMTkgXG4gTG9sbHlwb3AgUmVzcHJlc2VudHMgR2VuZGVyIiwNCiAgICAgICBjYXB0aW9uID0gIkNyZWF0ZWQgYnkgVmlTYSIsDQogICAgICAgeSA9ICIiLCB4ID0gIkNoYW5nZSBpbiBlbXBsb3ltZW50IGZyb20gMjAxOS0yMDIwIiwgDQogICAgICAgY29sID0gIkdlbmRlciIpDQpgYGANCg0KIyMjIyBSYWNlDQoNCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQoNCmVtcGxveWVkICU+JSANCiAgbmEub21pdCgpICU+JSANCiAgZmlsdGVyKHllYXIgJWluJSBjKDIwMTksIDIwMjApKSAlPiUgDQogIGFycmFuZ2UoeWVhcikgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBkaW1lbnNpb24sIHJhY2VfZ2VuZGVyLCBtYWpvcl9vY2N1cGF0aW9uKSAlPiUgDQogIHN1bW1hcmlzZShlbXBsb3lfbiA9IHN1bShlbXBsb3lfbikpICU+JSANCiAgDQogIGdyb3VwX2J5KG1ham9yX29jY3VwYXRpb24sIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIpICU+JSANCiAgc3VtbWFyaXNlKHJhdGlvID0gbGFzdChlbXBsb3lfbikgLyBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBjaGFuZ2UgPSByYXRpbyAtMSwNCiAgICAgICAgICAgIGVtcGxveWVkXzIwMTkgPSBmaXJzdChlbXBsb3lfbiksDQogICAgICAgICAgICBlbXBsb3lfMjAyMCA9IGxhc3QoZW1wbG95X24pKSAlPiUNCiAgbXV0YXRlKGluZHVzdHJ5ID0gZmN0X3Jlb3JkZXIobWFqb3Jfb2NjdXBhdGlvbiwgY2hhbmdlLCBzdW0pKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIA0KICBmaWx0ZXIoZGltZW5zaW9uID09ICJSYWNlIikgJT4lIA0KICANCiAgbXV0YXRlKG1ham9yX29jY3VwYXRpb24gPSBmY3RfcmVvcmRlcihtYWpvcl9vY2N1cGF0aW9uLCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBtYWpvcl9vY2N1cGF0aW9uLCBjb2wgPSByYWNlX2dlbmRlcikpICsNCiAgDQogIGdlb21fZXJyb3JiYXJoKGFlcyh4bWluID0gMCwgeG1heCA9IGNoYW5nZSksIGhlaWdodCA9IDAsDQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC42KSkgKw0KICBnZW9tX3BvaW50KGFlcyhzaXplID0gZW1wbG95ZWRfMjAxOSksDQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC42KSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBzaXplID0gMSkgKw0KICANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCksIGxpbWl0cyA9IGMoLS4yLC4xKSkgKw0KICBzY2FsZV9jb2xvcl90YWJsZWF1KGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSkgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoZ3VpZGUgPSBGQUxTRSkgKw0KICANCiAgbGFicyh0aXRsZSA9IHN0cl93cmFwKCIlIENoYW5nZSBpbiBFbXBseS4gYnkgTWFqb3IgT2NjdXBhdGlvbiIsIDM1KSwNCiAgICAgICBzdWJ0aXRsZSA9ICIoZnJvbTogMjAxOSB0byAyMDIwKSBcbiBcblNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIGVtcGx5ICMgaW4gMjAxOSBcbiBMb2xseXBvcCBSZXNwcmVzZW50cyBSYWNlIiwNCiAgICAgICBjYXB0aW9uID0gIkNyZWF0ZWQgYnkgVmlTYSIsDQogICAgICAgeSA9ICIiLCB4ID0gIkNoYW5nZSBpbiBlbXBsb3ltZW50IGZyb20gMjAxOS0yMDIwIiwgDQogICAgICAgY29sID0gIlJhY2UiKQ0KYGBgDQoNCg0KIyMjIG1pbm9yIG9jY3VwYXRpb24NCg0KIyMjIyBHZW5kZXINCg0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCg0KZW1wbG95ZWQgJT4lIA0KICBuYS5vbWl0KCkgJT4lIA0KICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxOSwgMjAyMCkpICU+JSANCiAgYXJyYW5nZSh5ZWFyKSAlPiUgDQogIGdyb3VwX2J5KHllYXIsIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIsIG1pbm9yX29jY3VwYXRpb24pICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveV9uID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICANCiAgZ3JvdXBfYnkobWlub3Jfb2NjdXBhdGlvbiwgZGltZW5zaW9uLCByYWNlX2dlbmRlcikgJT4lIA0KICBzdW1tYXJpc2UocmF0aW8gPSBsYXN0KGVtcGxveV9uKSAvIGZpcnN0KGVtcGxveV9uKSwNCiAgICAgICAgICAgIGNoYW5nZSA9IHJhdGlvIC0xLA0KICAgICAgICAgICAgZW1wbG95ZWRfMjAxOSA9IGZpcnN0KGVtcGxveV9uKSwNCiAgICAgICAgICAgIGVtcGxveV8yMDIwID0gbGFzdChlbXBsb3lfbikpICU+JQ0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfcmVvcmRlcihtaW5vcl9vY2N1cGF0aW9uLCBjaGFuZ2UsIHN1bSkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIkdlbmRlciIpICU+JQ0KICANCiAgbXV0YXRlKG1pbm9yX29jY3VwYXRpb24gPSBmY3RfcmVvcmRlcihtaW5vcl9vY2N1cGF0aW9uLCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKHggPSBjaGFuZ2UsIHkgPSBtaW5vcl9vY2N1cGF0aW9uLCBjb2wgPSByYWNlX2dlbmRlcikpICsNCiAgDQogIGdlb21fZXJyb3JiYXJoKGFlcyh4bWluID0gMCwgeG1heCA9IGNoYW5nZSksIGhlaWdodCA9IDAsDQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC42KSkgKw0KICBnZW9tX3BvaW50KGFlcyhzaXplID0gZW1wbG95ZWRfMjAxOSksDQogICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IC42KSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBzaXplID0gMSkgKw0KICANCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnRfZm9ybWF0KCksIGxpbWl0cyA9IGMoLS4yLC4xKSkgKw0KICBzY2FsZV9jb2xvcl90YWJsZWF1KGd1aWRlID0gZ3VpZGVfbGVnZW5kKHJldmVyc2UgPSBUUlVFKSkgKw0KICBzY2FsZV9zaXplX2NvbnRpbnVvdXMoZ3VpZGUgPSBGQUxTRSkgKw0KICANCiAgbGFicyh0aXRsZSA9IHN0cl93cmFwKCIlIENoYW5nZSBpbiBFbXBseS4gYnkgTWlub3IgT2NjdXBhdGlvbiIsIDM1KSwNCiAgICAgICBzdWJ0aXRsZSA9ICIoZnJvbTogMjAxOSB0byAyMDIwKSBcbiBcblNpemUgaXMgcHJvcG9ydGlvbmFsIHRvIGVtcGx5ICMgaW4gMjAxOSBcbiBMb2xseXBvcCBSZXNwcmVzZW50cyBHZW5kZXIiLA0KICAgICAgIGNhcHRpb24gPSAiQ3JlYXRlZCBieSBWaVNhIiwNCiAgICAgICB5ID0gIiIsIHggPSAiQ2hhbmdlIGluIGVtcGxveW1lbnQgZnJvbSAyMDE5LTIwMjAiLCANCiAgICAgICBjb2wgPSAiR2VuZGVyIikNCmBgYA0KDQojIyMjIFJhY2UNCg0KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCg0KZW1wbG95ZWQgJT4lIA0KICBuYS5vbWl0KCkgJT4lIA0KICBmaWx0ZXIoeWVhciAlaW4lIGMoMjAxOSwgMjAyMCkpICU+JSANCiAgYXJyYW5nZSh5ZWFyKSAlPiUgDQogIGdyb3VwX2J5KHllYXIsIGRpbWVuc2lvbiwgcmFjZV9nZW5kZXIsIG1pbm9yX29jY3VwYXRpb24pICU+JSANCiAgc3VtbWFyaXNlKGVtcGxveV9uID0gc3VtKGVtcGxveV9uKSkgJT4lIA0KICANCiAgZ3JvdXBfYnkobWlub3Jfb2NjdXBhdGlvbiwgZGltZW5zaW9uLCByYWNlX2dlbmRlcikgJT4lIA0KICBzdW1tYXJpc2UocmF0aW8gPSBsYXN0KGVtcGxveV9uKSAvIGZpcnN0KGVtcGxveV9uKSwNCiAgICAgICAgICAgIGNoYW5nZSA9IHJhdGlvIC0xLA0KICAgICAgICAgICAgZW1wbG95ZWRfMjAxOSA9IGZpcnN0KGVtcGxveV9uKSwNCiAgICAgICAgICAgIGVtcGxveV8yMDIwID0gbGFzdChlbXBsb3lfbikpICU+JQ0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfcmVvcmRlcihtaW5vcl9vY2N1cGF0aW9uLCBjaGFuZ2UsIHN1bSkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIlJhY2UiKSAlPiUgDQogIA0KICBtdXRhdGUobWlub3Jfb2NjdXBhdGlvbiA9IGZjdF9yZW9yZGVyKG1pbm9yX29jY3VwYXRpb24sIGNoYW5nZSkpICU+JSANCiAgDQogIGdncGxvdChhZXMoeCA9IGNoYW5nZSwgeSA9IG1pbm9yX29jY3VwYXRpb24sIGNvbCA9IHJhY2VfZ2VuZGVyKSkgKw0KICANCiAgZ2VvbV9lcnJvcmJhcmgoYWVzKHhtaW4gPSAwLCB4bWF4ID0gY2hhbmdlKSwgaGVpZ2h0ID0gMCwNCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjYpKSArDQogIGdlb21fcG9pbnQoYWVzKHNpemUgPSBlbXBsb3llZF8yMDE5KSwNCiAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjYpKSArDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGx0eSA9IDIsIHNpemUgPSAxKSArDQogIA0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIiwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSwgbGltaXRzID0gYygtLjIsLjEpKSArDQogIHNjYWxlX2NvbG9yX3RhYmxlYXUoZ3VpZGUgPSBndWlkZV9sZWdlbmQocmV2ZXJzZSA9IFRSVUUpKSArDQogIHNjYWxlX3NpemVfY29udGludW91cyhndWlkZSA9IEZBTFNFKSArDQogIA0KICBsYWJzKHRpdGxlID0gc3RyX3dyYXAoIiUgQ2hhbmdlIGluIEVtcGx5LiBieSBNaW5vciBPY2N1cGF0aW9uIiwgMzUpLA0KICAgICAgIHN1YnRpdGxlID0gIihmcm9tOiAyMDE5IHRvIDIwMjApIFxuIFxuU2l6ZSBpcyBwcm9wb3J0aW9uYWwgdG8gZW1wbHkgIyBpbiAyMDE5IFxuIExvbGx5cG9wIFJlc3ByZXNlbnRzIFJhY2UiLA0KICAgICAgIGNhcHRpb24gPSAiQ3JlYXRlZCBieSBWaVNhIiwNCiAgICAgICB5ID0gIiIsIHggPSAiQ2hhbmdlIGluIGVtcGxveW1lbnQgZnJvbSAyMDE5LTIwMjAiLCANCiAgICAgICBjb2wgPSAiUmFjZSIpDQpgYGANCg0KDQoNCiMjIyBJbmR1c3RyeSB3aXNlICUgY2hhbmdlDQoNCiMjIyMgVG90YWwNCg0KYGBge3J9DQpsaWJyYXJ5KGdncmVwZWwpDQpgYGANCg0KDQpgYGB7cn0NCmNvbXBhcmVfMjAxOV8yMDIwICU+JSANCiAgZmlsdGVyKGRpbWVuc2lvbiA9PSAiVG90YWwiKSAlPiUgDQogIG11dGF0ZShpbmR1c3RyeSA9IGZjdF9yZW9yZGVyKGluZHVzdHJ5LCBjaGFuZ2UpKSAlPiUgDQogIA0KICBnZ3Bsb3QoYWVzKGVtcGxveWVkXzIwMTksIGNoYW5nZSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IGluZHVzdHJ5KSwgc2l6ZSA9IDMpICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgY29sID0gInJlZCIpICsNCiAgDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB1bml0X2Zvcm1hdCh1bml0ID0gIk0iLCBzY2FsZSA9IDFlLTYpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50X2Zvcm1hdCgpKSArDQogIA0KICBsYWJzKHRpdGxlID0gIk92ZXJhbGwgJSBFbXBseSBDaGFuZ2UgZm9yIEluZHVzdHJpZXMiLA0KICAgICAgIHN1YnRpdGxlID0gIihpbjogMjAxOSB0byAyMDIwKSIpDQpgYGANCg0KIyMjIyBSYWNlDQoNCg0KYGBge3J9DQpjb21wYXJlXzIwMTlfMjAyMCAlPiUgDQogIGZpbHRlcihkaW1lbnNpb24gPT0gIlJhY2UiLA0KICAgICAgICAgcmFjZV9nZW5kZXIgPT0gIkFzaWFuIikgJT4lIA0KICBtdXRhdGUoaW5kdXN0cnkgPSBmY3RfcmVvcmRlcihpbmR1c3RyeSwgY2hhbmdlKSkgJT4lIA0KICANCiAgZ2dwbG90KGFlcyhlbXBsb3llZF8yMDE5LCBjaGFuZ2UpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWwgPSBpbmR1c3RyeSksIHNpemUgPSAzKSArDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGx0eSA9IDIsIGNvbCA9ICJyZWQiKSArDQogIA0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gdW5pdF9mb3JtYXQodW5pdCA9ICJNIiwgc2NhbGUgPSAxZS02KSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gcGVyY2VudF9mb3JtYXQoKSkgKw0KICANCiAgbGFicyh0aXRsZSA9ICJFbXBseSAlIENoYW5nZSBmb3IgQXNpYW5zIGluIEluZHVzdHJ5IiwNCiAgICAgICBzdWJ0aXRsZSA9ICIoaW46IDIwMTkgdG8gMjAyMCkiKQ0KYGBgDQoNCiMjIE1vcmUgRXhwbG9yYXRpb24NCg0KYGBge3J9DQplbXBsb3llZCAlPiUgDQogIG5hLm9taXQoKSAlPiUgcHVsbChyYWNlX2dlbmRlcikgJT4lIA0KICB0YWJsZSgpDQogIA0KZW1wbG95ZWQgJT4lIA0KICBuYS5vbWl0KCkgJT4lIHB1bGwoZGltZW5zaW9uKSAlPiUgDQogIHRhYmxlKCkNCmBgYA0KDQpTZWVtcyBsaWtlIHdlIGRvbnQgaGF2ZSBkYXRhIGZvciBHZW5kZXIgYW1vbmcgUmFjZXMsIHNvIHNraXBpbmcgdGhlIGFuYWx5c2lzIG9mIGNvbWJpbmF0aW9uIG9mIGJvdGguDQoNCmBgYHtyfQ0KZW1wbG95ZWQNCmBgYA0KDQpgYGB7cn0NCmVtcGxveWVkICU+JSANCiAgcHVsbChyYWNlX2dlbmRlcikgJT4lIA0KICB0YWJsZSgpDQpgYGANCg0KDQojIyBFbmQgb2YgdGhpcyBFREENCg0KDQoNCg0K